By framework
Next.js security — a production hardening reference
A Next.js production-hardening reference: a priority checklist plus the server/client boundary and env vars, dependency CVEs, Server Actions authorization, SSRF, headers/CSP, and rate limiting, with a self-verification checklist. Defensive, no attack steps.
For: anyone running a Next.js app (App Router assumed). No attack steps here — this is a working reference for hardening: a priority-ordered checklist, per-area guidance, and self-verification. For the cross-framework picture, see the security-by-framework hub.
Priority-ordered hardening checklist
Do this table top-down. P0 is a prerequisite, P1 is the most frequent source of incidents, P2 is ongoing operational hygiene.
P0 ── Prerequisite (do first)
Keep secrets out of the browser / dependency CVE monitoring + fast patching / firm production config
P1 ── Top source of incidents
Server Actions/Route Handlers authorization + input validation / SSRF on server fetches
P2 ── Operational hygiene
Headers/CSP / auth, session, cookies / rate limiting
| Priority | Control | Specifics (Next.js) |
|---|---|---|
| P0 | Secrets out of the browser | NEXT_PUBLIC_ only for browser-safe values; secrets only in Server Component/Action/Route Handler |
| P0 | Dependency CVEs | Monitor with npm audit/osv-scanner; judge by running version, patch fast. Keep up with core RCE |
| P0 | Production config | Run a production build; don't leak internals (stack/env) on errors |
| P1 | Action authorization | Authentication + owner-scoped authorization in every Server Action/Route Handler |
| P1 | Input validation | Schema-validate inputs (type/range/allowed). Don't trust the client |
| P1 | SSRF protection | Restrict server-side URL fetches to an allowlist + block internal IPs/metadata. Limit image remote patterns |
| P2 | Headers/CSP | Security headers + HSTS in next.config. Consider a nonce-based CSP on App Router |
| P2 | Auth/cookies | Secure/HttpOnly/SameSite session cookies. Don't leave authorization to middleware alone |
| P2 | Rate limiting | Limits on auth, Server Actions, and Route Handlers |
1. The server/client boundary and env vars (P0)
Next.js's biggest source of incidents is secrets that were meant to be server-only ending up in the client.
- Only prefix browser-safe values with
NEXT_PUBLIC_. Never on API keys or connection info (NEXT_PUBLIC_values are baked into the client bundle at build time and visible to visitors). - Read secrets only inside Server Components / Server Actions / Route Handlers, and keep them out of
propsand responses (serialized values). - Keep server-only modules from being imported by the client (accidental inclusion can bundle secrets). See .env files and secrets.
2. Dependency CVEs and the core (P0)
- Machine-monitor dependency (npm) CVEs with
npm auditor osv-scanner, judge by the running version, and patch fast (decide on what's actually installed, not the package.json declaration). - Next.js core has had serious RCEs, so keep up quickly when one is published. For the operating discipline see not falling behind on CVEs; for practice, the vulnerability-response playbook.
- Keep Node/Next on supported versions and don't leave EOL versions in place.
3. Server Actions / Route Handlers (authorization + validation, P1)
These are public server entry points. Being callable doesn't mean it's allowed.
Common (dangerous)
- actions treated as "logged in = allowed"
- relying on middleware auth alone, no ownership check
- input passed to DB or external calls unvalidated
- trusting client-supplied values (IDs, flags) as-is
Correct
- authentication plus owner/permission-scoped authorization in every action/handler
- don't leave it to middleware (authorize close to the data)
- schema-validate input (type/range/allowed)
- re-verify on the server so ID swaps don't work
See what IDOR is. Do an ownership check on every read/update/delete path.
4. SSRF and server-side fetches (P1)
Server-side fetching of user-supplied URLs (image proxies, webhooks, metadata fetches) is an SSRF entry.
- Restrict targets to an allowlist, and at connection time block reaching private IPs and cloud metadata (169.254.169.254).
- Keep image-optimization remote patterns to a minimum (don't allow fetching arbitrary hosts).
- See what SSRF is. This site routes outbound fetches through an SSRF-safe gateway.
5. Injection and output
- XSS: React escapes output by default. Don't pass user input to
dangerouslySetInnerHTML(only after sanitizing if truly needed). See what XSS is. - SQL/injection: bind with an ORM/placeholders; never build queries by string concatenation (→ what SQL injection is).
- Don't pass external input to dangerous evaluation like
eval.
6. Security headers and CSP (P2)
- Set security headers (X-Content-Type-Options, etc.) and HSTS in
next.config. Check your own site with the security headers checker. - On App Router, consider a nonce-based CSP (avoid blanket-allowing inline scripts). Note that coexisting with analytics/ad tags takes design.
7. Auth, session, cookies (P2)
- Set Secure / HttpOnly / SameSite on session cookies.
- Don't delegate authorization to middleware auth alone — middleware is a supplement; verify the actual decision in the action/handler/data layer (some paths can bypass middleware).
- Regenerate and expire sessions appropriately on login.
8. Rate limiting (P2)
- Apply attempt/throughput limits to auth, Server Actions, and Route Handlers to curb brute force, abuse, and DoS.
Verify: is your Next.js actually hardened?
Building it isn't the end — it's done only once you've checked. These are defensive self-checks against your own site/environment.
No secrets leaked to the client
NEXT_PUBLIC_.Production doesn't leak internals on errors
Action authorization holds
Headers, dependencies, SSRF
npm audit/osv is clean, and that outbound fetches can't reach internal IPs.This site's view: manage 'the boundary and dependencies,' not the core
This site runs on Next.js, and the center of gravity isn't flashy config but the server/client boundary and dependency freshness. Secrets stay on the server, public entry points (Server Actions/Route Handlers) always carry authorization and input validation, and dependencies get a CVE audit before every deploy. Our own origin was an incident of "unpatched CVE auto-exploited," so machine-monitoring dependencies is a top-priority habit. Outbound URL fetches go through an SSRF-safe gateway so they can't reach internal IPs or metadata.
Read next
- Hub: security by framework · Laravel security
- Dependencies: not falling behind on CVEs · the vulnerability-response playbook
- Glossary: what IDOR is · what SSRF is · .env files and secrets · XSS
- Tools: security headers checker
FAQ
QWhat should I do first to secure Next.js?
The three P0 items: (1) keep secrets out of the browser (only prefix browser-safe values with NEXT_PUBLIC_, never API keys or connection info); (2) machine-monitor dependency CVEs, judge by the running version, and patch fast (including core RCE); (3) firm up production config (run a production build; don't leak internals on errors). Next, move to Server Actions / Route Handlers authorization and input validation, and SSRF protection.
QHow do I handle environment variables safely?
The rule is 'secrets stay on the server.' Only prefix browser-safe values with NEXT_PUBLIC_; never on API keys or connection info (NEXT_PUBLIC_ values are baked into the client bundle at build time and visible to visitors). Read secrets only inside server components / Server Actions / Route Handlers, and design so they never slip into props or responses.
QWhat should I watch for with Server Actions?
Server Actions and Route Handlers are public server entry points. Being callable doesn't mean it's allowed. On top of login (authentication), write authorization that scopes every operation to the owner, and always validate input (e.g. schema validation). Don't rely on middleware auth alone — do the ownership check in the action/handler too.
QHow do I prepare for SSRF?
The main entry is server-side fetching of user-supplied URLs (image proxies, webhooks, metadata fetches). Restrict targets to an allowlist and, at connection time, block reaching private IPs and cloud metadata (169.254.169.254). Keep image-optimization remote patterns to a minimum. See the glossary for detail.
QHow do I manage npm dependency vulnerabilities?
Machine-monitor known CVEs with npm audit or osv-scanner, judge by the running version, and patch fast (decide on what's actually installed, not the package.json declaration). Next.js core has had serious RCEs, so keeping up quickly matters. Also keep Node/Next on supported versions and don't leave EOL versions in place.