CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-29927
9.192.90%

The Infinite Loophole: Bypassing Next.js Security with a Single Header

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 21, 2026·6 min read·23 visits

Active Exploitation

Executive Summary (TL;DR)

Next.js implemented a loop-prevention mechanism that trusted a specific header to track middleware recursion. Attackers can manually inject this header (`x-middleware-subrequest`) to convince the server that the limit has been reached, causing Next.js to skip security middleware and serve protected content.

A critical authorization bypass vulnerability in Next.js allows attackers to skip middleware execution entirely. By spoofing an internal recursion-tracking header, attackers can trick the server into believing a request has already been processed multiple times, causing it to bypass authentication checks and access protected routes directly. This affects all versions from 11.1.4 up to 15.2.2.

The Hook: When the Bouncer Takes Your Word for It

Middleware in Next.js is the unsung hero of modern React applications. It sits at the edge, acting as the bouncer for your routes. It checks if you have a session token, validates your permissions, rewrites paths based on your locale, and injects security headers like CSP. It is the gatekeeper. If the middleware doesn't run, the gate is effectively left wide open.

But middleware has a problem: recursion. Since middleware can rewrite requests to other paths which might trigger more middleware, there is a risk of creating an infinite loop that crashes the server (or at least the Vercel function, costing you a fortune in compute time). To solve this, Next.js needs a way to track how deep the rabbit hole goes.

The engineers implemented a solution that is logical on paper but catastrophic in practice: they used an HTTP header to count the loops. Specifically, x-middleware-subrequest. The server reads this header, counts the occurrences of the middleware name, and if it hits a hardcoded limit (usually 5), it assumes a loop is happening and... stops executing the middleware to save the process.

Here is the kicker: they trusted the client to provide the truth. They assumed that this header would only ever be present if the server put it there during an internal rewrite. They forgot the first rule of web security: Input is evil. If an attacker simply sends this header in their initial request, the server throws its hands up, says 'Whoa, too many loops!', skips the security checks, and hands over the data.

The Flaw: Trusting the Untrustable

The vulnerability stems from a classic logic flaw: relying on client-controlled data for server-side state management without validation. In versions of Next.js ranging from v12.2 to v15.2.2, the logic for handling the x-middleware-subrequest header shifted from a simple path check to a recursion depth check. The code looks for a colon-separated list of middleware names in the header.

Technically, the server parses x-middleware-subrequest. It splits the string by colons and counts how many times the current middleware's name appears. If that count exceeds MAX_RECURSION_DEPTH (which is set to 5), the runMiddleware function essentially returns early, passing the request downstream to the page handler or API route without running the user-defined logic in middleware.ts.

This is the architectural equivalent of a bank vault that locks automatically at 5:00 PM, but checks the time by looking at the customer's wristwatch. If you walk in at noon and tell the teller 'It's 5:01 PM', they unlock the vault and go home, leaving you inside. Because the header is processed before any user code runs, there is nothing a developer can write in their own middleware.ts to stop this. The framework fails before your code even loads.

The Code: Anatomy of a Bypass

Let's look at the logic that caused the issue. While the exact file paths vary by version, the core logic in the adapter.ts or next-server components effectively did this:

// Pseudocode of the vulnerable logic
const MAX_RECURSION_DEPTH = 5;
 
function getMiddlewareRecursion(req) {
  const header = req.headers.get('x-middleware-subrequest') || '';
  const depth = header.split(':').filter(n => n === middlewareName).length;
  return depth;
}
 
// Later in the request lifecycle...
if (getMiddlewareRecursion(req) >= MAX_RECURSION_DEPTH) {
  // Assume infinite loop, skip middleware execution
  return { finished: true }; 
}

The fix, introduced in commit 52a078da3884efe6501613c7834a3d02a91676d2 (and backported in 5fd3ae8f8542677c6294f32d18022731eab6fe48), introduces a shared secret. The server now generates a random token at startup. Internal sub-requests must sign the header with this token.

// The Fix: Validation of the source
if (requestHeaders.has('x-middleware-subrequest')) {
  const subrequestId = requestHeaders.get('x-middleware-subrequest-id');
  
  // Check if the secret matches what the server generated at startup
  if (subrequestId !== internalSecret) {
    // If it doesn't match, the client is spoofing it. Strip the header.
    requestHeaders.delete('x-middleware-subrequest');
  }
}

This ensures that only the Next.js server itself can increment the recursion counter. If an external attacker tries to inject the header, they won't know the random 8-byte hex string (stored in a Symbol in globalThis), so the server strips their fake header and runs the middleware as normal.

The Exploit: Bypassing Auth with Curl

Exploiting this requires zero coding skills and standard command-line tools. You don't need buffer overflows; you just need to know how to count to five.

The Scenario: You have a Next.js application protecting an admin panel at /admin. The middleware checks for a session cookie and redirects to /login if it's missing.

The Attack:

  1. Probe: Send a normal request to /admin. Receive 307 Temporary Redirect to /login.
  2. Craft: Construct a header that simulates 5 previous executions. The middleware name is almost always middleware or src/middleware.
  3. Fire:
curl -v http://target.com/admin \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"

The Result: The server sees the header, calculates depth = 5, triggers the loop prevention logic, skips the auth check, and returns 200 OK with the contents of the admin dashboard.

> [!WARNING] > In some setups, the middleware name might include the path, like pages/_middleware. Exploitation tools like Nuclei simply spray variants: src/middleware:middleware:pages/_middleware... to cover all bases.

The Impact: From Bypass to Cache Poisoning

The immediate impact is obvious: broken access control. If you use Next.js middleware to gate content, that gate is gone. Admin panels, user dashboards, and premium content are accessible to anyone.

However, the secondary impact is potentially worse: Web Cache Poisoning.

Many Next.js sites sit behind CDNs (Vercel Edge Network, Cloudflare, Fastly). If an attacker sends the exploit request and the CDN is configured to cache the response (even briefly), the CDN might cache the bypassed version of the page (the 200 OK admin panel) instead of the redirect.

Now, legitimate administrators or users navigating to that URL will be served the cached, exploited content. Or worse, if the page renders user-specific data (PII) relying on the middleware to filter it, an attacker could force the server to generate a page with their own malicious state, cache it, and serve it to victims. This turns a targeted bypass into a broad Denial-of-Service or Information Disclosure event.

The Fix: Patch or Block

The vulnerability is patched in Next.js versions 15.2.3, 14.2.25, 13.5.9, and 12.3.5. The patch logic relies on stripping the malicious header if a corresponding secret ID is absent.

Immediate Remediation Strategy:

  1. Upgrade: Update your next dependency immediately. npm install next@latest.
  2. Verify: Ensure your lockfile actually updated the resolved version.

Mitigation (If you cannot upgrade): If you are stuck on a legacy version or cannot deploy immediately, you must implement a block at your network edge.

Nginx Configuration:

# Drop the header before it hits the node process
proxy_set_header x-middleware-subrequest "";

Cloudflare WAF Rule: Create a firewall rule blocking any request where the header x-middleware-subrequest exists. Since this header is internal-only, legitimate clients (browsers) never send it. It is safe to drop all external traffic containing it.

Official Patches

VercelGitHub Security Advisory with patch instructions

Fix Analysis (2)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
EPSS Probability
92.90%
Top 0% most exploited

Affected Systems

Next.js v11.1.4 - 12.3.4Next.js v13.0.0 - 13.5.8Next.js v14.0.0 - 14.2.24Next.js v15.0.0 - 15.2.2

Affected Versions Detail

Product
Affected Versions
Fixed Version
Next.js
Vercel
11.1.4 - 12.3.412.3.5
Next.js
Vercel
13.0.0 - 13.5.813.5.9
Next.js
Vercel
14.0.0 - 14.2.2414.2.25
Next.js
Vercel
15.0.0 - 15.2.215.2.3
AttributeDetail
CWE IDCWE-285 (Improper Authorization)
Attack VectorNetwork (HTTP Headers)
CVSS9.1 (Critical)
EPSS Score0.92896 (92.90%)
ImpactFull Auth Bypass
Exploit StatusActive / POC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1078Valid Accounts
Defense Evasion
T1557Man-in-the-Middle
Credential Access
CWE-285
Improper Authorization

The software does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.

Known Exploits & Detection

GitHubProof of concept demonstrating the bypass using fetch/curl.
NucleiAutomated detection template checking for middleware bypass.
NucleiDetection Template Available

Vulnerability Timeline

Vulnerability reported to Vercel by zhero and inzo_
2025-02-27
Patched versions released (15.2.3, etc.)
2025-03-18
CVE-2025-29927 published
2025-03-21
Public exploits and Nuclei templates released
2025-03-23

References & Sources

  • [1]Original Research: Next.js and the Corrupt Middleware
  • [2]Assetnote Deep Dive Analysis
Related Vulnerabilities
CVE-2024-34351CVE-2023-46298

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.