Vulnerabilities

7 min readUpdated

CVE-2025-29927: the Next.js middleware authorisation bypass

Quick answer

CVE-2025-29927 is an authorisation bypass in Next.js. The framework used an internal header, x-middleware-subrequest, to stop middleware recursing; by sending that header, an external attacker could make Next.js skip middleware entirely. Apps that enforced authentication in middleware could be bypassed with a single request. It scored CVSS 9.1, was disclosed on 21 March 2025, and affects Next.js from 11.1.4 up to the fixes in 12.3.5, 13.5.9, 14.2.25 and 15.2.3. This is a rare case where an edge rule genuinely helps.

At a glance

critical severity
Identifier
CVE-2025-29927
Also known as
Next.js middleware authorisation bypass
Product
Next.js (self-hosted, App and Pages Router)
Affected
11.1.4 ≤ Next.js < 12.3.5; 13.0.0 ≤ Next.js < 13.5.9; 14.0.0 ≤ Next.js < 14.2.25; 15.0.0 ≤ Next.js < 15.2.3
Fixed in
12.3.5; 13.5.9; 14.2.25; 15.2.3
CVSS
9.1 (CVSS 3.1, GitHub as CNA)
Disclosed
Known exploited (CISA KEV)
Not listed

Patched. Public analysis and proof-of-concept exist; trivially exploitable where auth is enforced only in middleware.

01What is CVE-2025-29927?

CVE-2025-29927 is an authorisation bypass in Next.js. Middleware in Next.js runs before routing and rendering, which made it a tempting place to put authentication and access checks — redirect unauthenticated users, block admin routes, and so on. The framework used an internal header, x-middleware-subrequest, to detect and short-circuit its own internal sub-requests so middleware would not run recursively.

The flaw was that this header was trusted when it arrived from outside. An attacker who simply added x-middleware-subrequest to a request could make Next.js believe middleware had already run and skip it. If your authorisation lived in that middleware, it was skipped too, and the request reached the protected route unchecked. No credentials, session or special tooling were needed.

02Which versions and deployments are affected?

Affected releases span from Next.js 11.1.4 up to the fixes. What matters as much as the version is how you deploy: the bypass needs your own server to make the middleware decision, so self-hosted deployments using next start or output: 'standalone' were affected, while some managed platforms that run routing separately were not.

Deployment / versionAffected?Note
Self-hosted next start / standalone < fixYesThe server itself evaluates middleware
Static export (output: 'export')NoNo middleware runtime exists
Vercel-hostedNoRouting runs decoupled from the app
Netlify / Cloudflare Workers adaptersNoRouting decoupled for the same reason
Next.js ≥ 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3FixedHeader validated and filtered

03How the bypass works, conceptually

Next.js read the x-middleware-subrequest header and, past a depth threshold, concluded that middleware had already executed and should be skipped to avoid an infinite loop. Because the check did not distinguish an internal marker from a client-supplied one, a request arriving from the internet with that header set would satisfy the condition and bypass middleware. In later versions the depth was a small fixed number, so a short, static header value was enough — there was nothing to brute-force.

The impact depended entirely on what the middleware did. If it only rewrote URLs or set headers, the bypass was mostly cosmetic. If it enforced authentication or authorisation — the common pattern the advisory warned against — then skipping it exposed whatever it was protecting. That is why the fix came with the standing advice that middleware should never be the sole line of defence.

04How to check if you are affected

Confirm two things: the resolved Next.js version is at or above the fix for your line, and whether you self-host the server runtime. If you are below the fix and running next start or a standalone output, and any of your middleware performs authorisation, assume you are exploitable until patched.

Check the resolved Next.js version and how you deploy
# Resolved version, not the range in package.json
node -p "require('next/package.json').version"
npm ls next 2>/dev/null

# Are you self-hosting the server runtime?
grep -E '"(build|start)"|output' package.json next.config.* 2>/dev/null
#   output: 'export'      -> static, not affected
#   next start / standalone -> affected if version < fix

05How to fix it: patch and defend in depth

Upgrade Next.js to 15.2.3, 14.2.25, 13.5.9 or 12.3.5, whichever matches your line. The patched versions validate the internal header and filter it out when it fails validation, so an external client can no longer use it to skip middleware. Treat those as minimums for this CVE only: Next.js published further middleware and proxy bypass advisories in 2026, such as CVE-2026-44573 and CVE-2026-45109, that were fixed only in the 15.5.x and 16.x lines, so the safe target is the newest release of a supported line. Then fix the design issue the bug exposed: enforce authorisation where the data is served, not only in middleware.

  • Upgrade to the fixed release for your major line, and pick up CVE-2025-30218's fix at the same time
  • Move authentication and authorisation checks into route handlers, server actions and the data layer — the places that actually return data
  • Treat middleware as an optimisation and a first filter, never as your only gate
  • As an immediate, independent mitigation, strip the x-middleware-subrequest header at your reverse proxy or WAF

06An edge rule that genuinely helps

Most of the vulnerabilities on these pages cannot be meaningfully filtered at the edge. This one can, which makes it the clearest example of a virtual patch that works. Because the attack depends on a single, specific request header that ordinary browsers never send, stripping or rejecting that header at a reverse proxy in front of Next.js stops the bypass — and it is exactly the mitigation the vendor recommended for teams that could not upgrade immediately. One caveat: Next.js attaches the header to fetch requests made from middleware, so a reject rule can break middleware that calls an API or auth service behind the same proxy, and stripping removes the loop guard if middleware fetches its own site through it. Cloudflare made its managed rule opt-in for that reason, after sites using third-party auth vendors saw failing requests. Run a new rule in log-only mode first.

You have two clean options at the edge: refuse any external request that carries the header, or quietly drop the header before forwarding so the application never sees a client-supplied value. The nginx snippet below shows both; it was validated with nginx -t and checked functionally against a loopback upstream. It is a genuine stopgap, but it is still a stopgap — upgrade Next.js and move authorisation into your handlers so you are not relying on a single header rule.

Strip or reject the internal header at nginx (validated with nginx -t, nginx 1.22, Debian 12)
server {
    # Option A: refuse any request that arrives carrying the internal header.
    if ($http_x_middleware_subrequest) {
        return 403;
    }

    location / {
        proxy_pass http://nextjs_upstream;   # your upstream {} block
        proxy_http_version 1.1;
        # proxy_set_header here replaces any inherited from server/http: repeat them.
        proxy_set_header Host $host;
        # Option B: never forward the header, whatever the client sent.
        # An empty value tells nginx not to pass the field upstream.
        proxy_set_header X-Middleware-Subrequest "";
    }
}

07Disclosure timeline

The episode is a clean lesson in defence in depth. A single misplaced trust decision in a framework turned a convenience header into an authorisation bypass, and the systems that survived unscathed were the ones that did not rely on middleware alone. Pair your patch with real checks at the data layer, and keep an edge rule in place as cheap insurance.

DateEvent
27 Feb 2025Reported to the Next.js team via private disclosure
14 Mar 2025Vulnerability confirmed; remediation begins
17–18 Mar 202514.2.25 and 15.2.3 released; CVE issued
21 Mar 2025CVE-2025-29927 made public
22–23 Mar 202513.5.9 and 12.3.5 back-ports released

Questions

Frequently asked questions

You are affected if you run a self-hosted Next.js between 11.1.4 and the fix (12.3.5, 13.5.9, 14.2.25 or 15.2.3) using next start or a standalone output, and any middleware performs authorisation. Static exports have no middleware runtime, and some managed platforms run routing separately and were not affected. Check your resolved version and deployment model.

Yes, unusually for a framework vulnerability. The attack relies on one specific header that browsers never send, so stripping or rejecting x-middleware-subrequest at a reverse proxy or WAF blocks the bypass, as the vendor recommended. Test first: middleware that fetches an API or auth service through the same proxy also carries the header, which is why Cloudflare made its rule opt-in. Still upgrade as well.

The impact depends on what the middleware does. If it only rewrites URLs or sets headers, bypassing it is largely cosmetic. The serious cases are apps that enforce authentication or authorisation in middleware, because skipping it then exposes protected routes. Either way, patch, and do not rely on middleware as your only access control.

In the code that actually returns data: route handlers, server actions and the data-access layer. Middleware runs before routing and is a fine first filter or optimisation, but it should never be the sole gate. Checking authorisation close to the data means a middleware bypass cannot hand an attacker protected content.

It is not listed in CISA KEV at the time of writing. It is nonetheless trivially exploitable where authorisation is enforced only in middleware, and public analysis and proof-of-concept exist, so it should be treated as high priority regardless of KEV status. Patch promptly and strip the header at the edge.

Sources

Sources and verification

The nginx header-strip and header-reject snippet was syntax-checked with nginx -t (nginx 1.22.1, with an upstream block added) and verified functionally against a loopback echo upstream (403 when the header is present; header absent upstream when stripped); the node -p and grep checks were run against a sample project with Node.js 22 on Debian 12, October 2026. npm ls was not executed.

  1. 01NVD — CVE-2025-29927 · NVD
  2. 02GHSA-f82v-jwr5-mffw — Authorization Bypass in Next.js Middleware · GitHub Security Advisories
  3. 03Postmortem on Next.js Middleware bypass · Vercel
  4. 04Next.js and the corrupt middleware (researcher write-up) · zhero;
  5. 05nginx proxy_set_header documentation · nginx.org
  6. 06New Managed WAF rule for Next.js CVE-2025-29927 (opt-in note) · Cloudflare
  7. 07GHSA-223j-4rm8-mrmf — x-middleware-subrequest-id may be leaked to external hosts (CVE-2025-30218) · GitHub Security Advisories
  8. 08GHSA-26hh-7cqf-hhc6 — Middleware / Proxy bypass via segment-prefetch routes (CVE-2026-45109) · GitHub Security Advisories
  9. 09GHSA-36qx-fr4f-26g5 — Middleware / Proxy bypass in Pages Router applications using i18n (CVE-2026-44573) · GitHub Security Advisories

Last updated