Next.js Security Playbook (Checklist + Cheatsheet)
TL;DR
- Clarify scope first, then work systematically.
- User input + RSC or
dangerouslySetInnerHTML= high XSS risk. postMessagewithout 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]
generateMetadatauses 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.originvalidated? - [x]
event.sourcevalidated? - [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.
postMessagewithout origin checks is not a feature, it is a bug.- RSC XSS happens pre-hydration and has maximum impact.