For Next.js developers using versions 11.1.4 through 15.2, there was a recent security bug in Next.js (CVE-2025-29927), that let attackers skip middleware checks and reach protected parts of a site. This is due to how Next.js handles this header x-middleware-subrequest which allows hackers to trick Next.js into thinking middleware already ran.

This only affects apps not hosted by Vercel or Netlify and runs with next start. To fix this, you can update to the most recent fixed releases. If you cannot update your Next.js version now, block or remove the header and add extra auth checks in your routes and API logic.

What happened

Next.js has a system to stop middleware from running in a loop. It uses a special header called x-middleware-subrequest to count how many times middleware runs.

If it runs too many times (5 by default), Next.js skips middleware to avoid an endless loop.

The problem is, anyone can set this header themselves.

Hackers can fake the header, make it look like middleware already ran too much, and Next.js will skip all security checks.

Here’s a basic idea of how it works:

const subrequests = request.headers.get('x-middleware-subrequest')?.split(':') || [];
const depth = subrequests.filter(s => s === middlewareName).length;

if (depth >= MAX_RECURSION_DEPTH) {
  return NextResponse.next(); // this skips middlewares
}

What hackers do

They send a fake request to a protected endpoint. In their fake request, they manually add the header x-middleware-subrequest with lots of fake entries. Here is an example:

GET /protected-page
x-middleware-subrequest: auth:auth:auth:auth:auth

Now, when Next.js receives that request, it will think:

"this middleware already ran 5 times. I should skip it now."

But in reality, middleware never ran even once, the hacker just tricked it.

Who is affected

This issue only affects apps that are self hosted and uses next start with the standalone output. If your app is deployed on Vercel, Netlify, or your site is just a static file, you are not affected.

How to fix

  1. Update Next.js now
    • 12.x → 12.3.5
    • 13.x → 13.5.9
    • 14.x → 14.2.25
    • 15.x → 15.2.3
  2. Block or remove the header
    • In NGINX:
location / {
          proxy_set_header x-middleware-subrequest "";
  • In Apache:
RequestHeader unset x-middleware-subrequest
  • In Cloudflare’s WAF, add a rule that blocks any incoming request that contains the header called x-middleware-subrequest.

Always add extra checks and don’t just trust middleware only

Don’t only rely on middleware, always add extra layers of authorization:

  • In your page code
  • In your API routes
  • In your database

For example, if your dashboard shows private info, the API should still check if the user is logged in and authorized to view the requested data. Even if someone skips the middleware, they still won't get the data.

For more information regarding this critical flaw, visit the official Vercel’s blog.