Skip to main content
Published
SecurityOWASPNext.js

OWASP Top 10 for Next.js apps

OWASP Top 10 mapped to Next.js: Server Actions, Route Handlers, middleware, RSC, cookies, and the footguns that show up in real App Router products.

OWASP Top 10 still applies to Next.js. The framework just moves the failure points. Server Components, Server Actions, Route Handlers, and middleware give you more server surface in the same repo as the UI. That is useful. It is also easy to treat as safe by default when it is not.

This is the Next.js reading of the Top 10. App Router, same-origin BFFs behind rewrites, and the habits I use when shipping product apps on React and TypeScript.

1. Broken access control

In Next.js the UI is not the boundary. A Server Action is a public HTTP endpoint with a generated id. A Route Handler is an API. Middleware that only checks "cookie exists" is not authorization.

Every Server Action and Route Handler that reads or mutates data needs its own authz check on the server. Object-level checks matter: this session may edit this record, not any id the client posts. RSC can also leak data if you fetch wide and pass everything into a Client Component.

  • Authz inside the action or handler, not only in the page.
  • Never trust a user id, role, or plan field from the client body.
  • Do not use middleware alone as your access-control story.
  • Test two accounts against the same action in CI.

2. Cryptographic failures

NEXT_PUBLIC_ values ship to the browser. Secrets do not belong there. Session cookies should be HttpOnly, Secure, and SameSite with intent. Prefer the cookies() helpers on the server over rolling your own header parsing.

If you terminate TLS at a proxy, make sure the app still treats the request as HTTPS for secure cookies. Do not store access tokens in localStorage from a Client Component. If you need JWTs, keep them behind a BFF cookie boundary.

3. Injection

Server Actions and Route Handlers are where SQL and command injection show up when someone concatenates strings into a query. Use parameterized queries or a typed query builder.

XSS in Next.js is usually dangerouslySetInnerHTML, CMS HTML, markdown renderers, or reflecting searchParams into the DOM without care. React escapes text nodes. It does not save you from raw HTML. Sanitize at the boundary before render.

4. Insecure design

Shipping Server Actions for every mutation without rate limits, abuse controls, or step-up checks is insecure design. So is exposing expensive AI or email flows on a public action because the button is "behind login" in the UI.

Design the threat before the form. Ask what happens at abuse volume, what a stolen session can do, and which actions need confirmation. Feature flags help you dark-launch. They are not an auth layer.

5. Security misconfiguration

Missing security headers, open redirects in next.config redirects/rewrites, verbose digests in production errors, and CORS that mirrors any Origin are classic Next footguns.

Set a CSP that matches how you actually load scripts and images. Lock down draft mode and preview routes. Keep NODE_ENV and debug flags honest in production. If you rewrite to an internal BFF, do not accidentally expose that upstream on a public path.

6. Vulnerable and outdated components

Your Next.js version, React, and the npm tree are part of the attack surface. Framework CVEs happen. So do transitive package issues.

Pin versions with a lockfile. Run audits in CI. Upgrade Next on a schedule you can keep, not only when something breaks. Remove UI kits and helpers you stopped using.

7. Identification and authentication failures

Auth.js, Clerk, Cognito, or a first-party BFF session can all be fine. Misconfiguration is the usual failure: weak cookie settings, long-lived tokens in the client, middleware matcher gaps that leave /api or a Server Action path unprotected, and logout that clears UI state but not the cookie.

Protect login, callback, and password-reset Route Handlers with rate limits. Invalidate server session state on logout. Treat matcher misses as production bugs.

8. Software and data integrity failures

Webhook Route Handlers must verify signatures before you trust payment or auth events. Unsigned CI deploys and unchecked dependency updates belong in the same bucket.

Pin GitHub Actions where you can. Do not load remote scripts into layout.tsx from a CDN you do not control without Subresource Integrity when that is an option.

9. Security logging and monitoring failures

Server Actions can fail closed and still leave you blind. Log auth failures, forbidden actions, and spikes on login or billing routes. Do not log cookies, Authorization headers, or full JWTs.

Wire Next.js and BFF logs into something you actually watch. A 403 storm on an action is a signal. A pretty error page is not.

10. Server-Side Request Forgery (SSRF)

Server Components, Server Actions, and Route Handlers that fetch(userUrl) are SSRF candidates. So are link previews, OG scrapers, and "import from URL" features.

Allowlist schemes and hosts. Block localhost, link-local, and cloud metadata ranges. Be careful with image pipelines and any proxy-style Route Handler. The server should not become an open browser into your VPC.

Next.js habits that keep this real

I review Server Actions like public APIs. I keep secrets off the client bundle. I put session material in HttpOnly cookies, often behind a same-origin BFF rewrite. I test access control with more than one user.

OWASP Top 10 does not change because you use the App Router. The implementation details do. Map each item to an action, a handler, a cookie, or a dependency, and the list stops being abstract.

More writing

Availability

Open to opportunities

Open to senior product engineer roles with real ownership across the stack. Security-minded by default.

UK-based · Remote / hybrid · Permanent or contract