TL;DR

  • Clarify scope first, then work systematically.
  • User input + RSC or dangerouslySetInnerHTML = high XSS risk.
  • postMessage without origin checks is almost always a bug.

0. Scope

  • [x] Pages Router (/pages)
  • [x] App Router (/app)
  • [x] React Server Components (RSC)
  • [x] Middleware (middleware.ts)
  • [x] API Routes (/api/*)
  • [x] Edge Functions
  • [x] OAuth / SSO
  • [x] Dashboard / Account

1. Rendering and Injection (XSS)

1.1 dangerouslySetInnerHTML

  • [x] Used anywhere?
  • [x] Contains user input?
  • [x] Sanitized on the server?
  • [x] Markdown has a sanitizer?

Risk: user input + no sanitization = critical.

1.2 RSC / Flight Data

  • [x] User input appears in Flight stream?
  • [x] URL params (slug, lang, country) validated?
  • [x] Error pages (404/500) include input?
  • [x] generateMetadata uses input?

Note: pre-hydration XSS is possible.

1.3 Classic DOM sinks

  • [x] innerHTML
  • [x] outerHTML
  • [x] insertAdjacentHTML
  • [x] document.write
  • [x] <script>{variable}</script>

2. postMessage / Cross-Window

2.1 Sender

  • [x] postMessage(..., "*")
  • [x] Sensitive data in payload?
    • [x] Token
    • [x] Session
    • [x] Role
    • [x] Success flags
  • [x] Predictable callId?

2.2 Receiver

  • [x] event.origin validated?
  • [x] event.source validated?
  • [x] Schema validation?
  • [x] Type checks?

Risk: wildcard + no checks = high/critical.

2.3 Quick attacks

window.addEventListener("message", (e) => console.log(e.data))
postMessage({ success: true, role: "admin" }, "*")

3. Routing and Params

3.1 Dynamic Routes

  • [x] [slug]
  • [x] [[...catchall]]
  • [x] URL-encoding tested?
  • [x] HTML/JS payloads tested?

3.2 Search Params

  • [x] searchParams.get()
  • [x] Passed into:
    • [x] JSX
    • [x] Metadata
    • [x] API calls
    • [x] DB queries

4. API Routes (/api)

  • [x] Auth check present?
  • [x] Method whitelist?
  • [x] Input validation (zod / yup)?
  • [x] Rate limiting?
  • [x] Verbose errors?

4.1 Dangerous APIs

  • [x] exec, spawn
  • [x] fs.readFile
  • [x] fetch(userInput)
  • [x] SQL raw queries

Risk: SSRF / RCE.

5. Middleware and Headers

5.1 Middleware

  • [x] Auth only client-side?
  • [x] Header trust (x-forwarded-*)?
  • [x] Open redirects?

5.2 Security Headers

  • [x] CSP
  • [x] X-Frame-Options
  • [x] X-Content-Type-Options
  • [x] Referrer-Policy

Note: missing CSP increases XSS impact.

6. Auth / Session

  • [x] JWT in localStorage?
  • [x] Cookies httpOnly?
  • [x] postMessage in auth flow?
  • [x] OAuth redirect handling?
  • [x] Session fixation?

7. Typical red flags (cheatsheet)

Pattern Risk
dangerouslySetInnerHTML XSS
postMessage("*") Token leak
generateMetadata(userInput) Stored XSS
RSC + URL params Pre-hydration XSS
API without auth IDOR
fetch(userInput) SSRF
Verbose errors Info leak

8. Quick tests

XSS:

"><img src=x onerror=alert(1)>

RSC:

/%3Cscript%3Ealert(1)%3C/script%3E

postMessage:

postMessage({ success: true }, "*")

SSRF:

http://127.0.0.1:80
file:///etc/passwd

9. Severity mapping

Finding Severity
Token via postMessage Critical
Auth bypass Critical
Stored XSS High
Reflected XSS Medium
Info leak Low

Memory lines

  • Next.js is safe until user input reaches Server Components.
  • postMessage without origin checks is not a feature, it is a bug.
  • RSC XSS happens pre-hydration and has maximum impact.