Fix cards for TypeScript and Next.js
A01:2025 Broken Access Control
- Missing object-level authorization (IDOR and BOLA)CWE-862 · CWE-639 · CWE-863
Get the user from your authentication inside each route handler and server action, never from the request, and put one scope in every invoice query: tenant_id = $tenant AND (owner_id = $user OR $isBillingAdmin).
- Open redirectCWE-601
Resolve next against your own origin with new URL(next, site), the WHATWG parser browsers use, and pass the result to redirect() only if url.origin is in an exact allowlist and the URL has no user name or password; otherwise redirect to a fixed page.
- Path traversalCWE-22 · CWE-23 · CWE-36 · CWE-59
Check where the path lands, not what it looks like: resolve base with fs.realpath, resolve the request with realpath(path.resolve(base, name)), which collapses ../ and follows symlinks, and serve it only if it starts with base + path.sep.
- Server-side request forgery (SSRF)CWE-918
Attach the policy to the connection, not the hostname string.
A05:2025 Injection
- Cross-site scripting (XSS)CWE-79
Render user text as React children and attributes, which React escapes, and keep it out of dangerouslySetInnerHTML; if a field must carry HTML, sanitize it with DOMPurify first.
- OS command and argument injectionCWE-78 · CWE-88
Run the program directly with its arguments as a list, execFileSync(tool, ['--', name]), so no shell parses them, and put '--' before any user operand so a leading dash cannot pose as an option.
- SQL injectionCWE-89
Bind every value: put ? placeholders in the SQL and pass the values to the driver, as in db.prepare(sql).all(name, status), inside the route handler's data layer.
A06:2025 Insecure Design
- ClickjackingCWE-1021
Send a framing policy on sensitive pages, in middleware so every matched response carries it.
- Unrestricted file uploadCWE-434 · CWE-646 · CWE-73 · CWE-770
Decide the type from the bytes, not from file.type or the name.
A07:2025 Authentication Failures
- JWT validation in APIs (bearer tokens)CWE-347 · CWE-287
Verify the bearer token inside the route handler with jose's jwtVerify(): the issuer's public key from configuration, algorithms: ['RS256'], issuer and audience, requiredClaims: ['exp', 'sub'] and a small clockTolerance.
- Missing authentication for a critical functionCWE-306 · CWE-287
Verify a credential on the server in every protected route handler.
A08:2025 Software or Data Integrity Failures
- Mass assignment (over-posting)CWE-915
Never pass await request.json() or Object.fromEntries(formData) to Object.assign, a spread or an ORM create or update.
Not covered in Next.js yet
These weaknesses have fix cards in other stacks but not in this one.
- Cross-site request forgery (CSRF)
- CORS misconfiguration on credentialed APIs
- XML external entity (XXE) processing
- Insecure randomness for security tokens
- Weak password hashing
- Code injection
- CSV formula injection
- LDAP filter injection
- NoSQL operator injection
- Server-side template injection
- XPath injection
- Regular-expression denial of service (ReDoS)
- Unbounded resource consumption
- Hard-coded secrets
- Improper TLS certificate validation
- Session fixation and session cookies
- Insecure deserialization
- CRLF injection in logs and response headers
Supported versions
The latest major is in Active LTS; the previous major gets critical and security fixes only, until two years after its first release. Next.js support policy.
| Version | Latest | Status | Released | End of support |
|---|---|---|---|---|
| 16.x | 16.4.0 | SupportedActive LTS until 17.x ships; the cards use it. | 21 October 2025 | 21 October 2027 |
| 15.x | 15.5.27 | MaintenanceMaintenance LTS (critical and security fixes) for two years after its release, so until 2026-10-21; move to 16.x. | 21 October 2024 | 21 October 2026 |
| 14.x | 14.2.35 | End of life | 26 October 2023 | 26 October 2025 |
| Version | Latest | Status | Released | End of support |
|---|---|---|---|---|
| 26 | 26.11.1 | SupportedCurrent release until 2026-10-27; Active LTS from 2026-10-28 and Maintenance LTS from 2027-10-20 on the release schedule. | 5 May 2026 | 30 April 2029 |
| 24 | 24.21.0 | SupportedActive LTS until 2026-10-19; Maintenance LTS from 2026-10-20 on the release schedule. | 6 May 2025 | 30 April 2028 |
| 22 | 22.23.3 | MaintenanceMaintenance LTS since 2025-10-21. | 24 April 2024 | 30 April 2027 |
Next.js 16 requires Node.js 20.9 or later; run an Active or Maintenance LTS line, since Node.js 20 is past its end of life. Node.js release schedule
Minimum secure versions
The lowest release in each supported line that fixes every published advisory listed here. Anything older is missing a security fix.
| Package | At least | Why |
|---|---|---|
next | 16.3.8 | Seven advisories fixed on 30 September 2026, such as SSRF in Image Optimization (CVE-2026-94483) and cache poisoning (CVE-2026-94484, CVE-2026-94543); earlier 2026 releases fixed proxy (middleware) bypasses and remote code execution. Advisory |
next | 15.5.27 | CVE-2026-94484, CVE-2026-94543 and CVE-2026-94485 for 15.x, whose support ends on 2026-10-21; after that, only 16.x gets fixes. Advisory |
node | 22.23.2, 24.18.1 or 26.5.1 | The 29 July 2026 security releases, the latest on 11 October 2026: an HTTP/2 use-after-free (CVE-2026-56848), a Permission Model bypass (CVE-2026-58043), HTTP/2 memory exhaustion in 22.x and 24.x (CVE-2026-56846) and eight lower-severity CVEs. Advisory |
Middleware and security order
- Headers in
next.config: Set security headers withheaders()(or in proxy for a CSP nonce) andpoweredByHeader: false. - Proxy (formerly middleware):
proxy.tsruns before routes on the paths its matcher selects. Use it for redirects and coarse checks, never as the only authorization: matchers can skip paths and server functions, and CVE-2025-29927 and the 2026 proxy bypasses showed it can be skipped. - Route handlers and server actions: Authenticate and authorize inside each one, through a
server-onlydata access layer; Next.js says an exported server action can be called with a direct POST. - Server action origin check: Next.js rejects an action whose
Originhost differs from the request's host; addexperimental.serverActions.allowedOriginsonly for proxies you run. - Rendering: Server and client components render text through React's escaping; return only the fields the page needs.
Secure defaults and settings
| Setting | Value | Why |
|---|---|---|
poweredByHeader | true (sends X-Powered-By: Next.js) | Set false. |
serverActions.bodySizeLimit | 1 MB | Lower it where actions take small inputs. |
| Server action origin check | On in development and production | Keep allowedOrigins to hosts you control. |
NEXT_PUBLIC_ environment variables | Inlined into the client bundle | Never give a secret that prefix. |
Escape hatches to search for
Framework APIs that switch a protection off. Each one is sometimes needed; search for them in review and make each use justify itself.
| API | Risk | Instead |
|---|---|---|
dangerouslySetInnerHTML | Inserts HTML without escaping. | Render text, or sanitize first; escape < in JSON written into a script tag. |
Authorization only in proxy.ts | Matchers and bypasses leave routes and server functions open. | Check in each route handler and action. |
redirect() or NextResponse.redirect() with a URL from the request | Open redirect; redirect() does not validate its argument. | Resolve against your origin and compare with an allowlist. |
experimental.serverActions.allowedOrigins with broad wildcards | Weakens the CSRF check for server actions. | Name the exact hosts. |
Prisma $queryRawUnsafe or Drizzle sql.raw() | SQL injection. | $queryRaw tagged templates or sql with placeholders. |
Checklist, mapped to ASVS 5.0.0
- v5.0.0-8.3.1 Authorization runs in server code (route handlers, actions, the data access layer), never only in proxy or the client.
- v5.0.0-8.2.2 Each action and route handler checks the caller owns the object.
- v5.0.0-3.2.2 User content renders as text through React, not through
dangerouslySetInnerHTML. - v5.0.0-3.5.1 Server actions keep the origin check; cookie-authenticated route handlers that change state check
Originor a token. - v5.0.0-15.3.1 Server code returns only the fields the client needs.
- v5.0.0-9.1.1 Bearer tokens are verified with jose (or similar) before any claim is read.
- v5.0.0-13.4.6
poweredByHeaderis off. - v5.0.0-15.2.1 Next.js is at or above the minimum secure version for its line.