CVE-2025-29927 – Authorization Bypass Vulnerability in Next.js: All You Need to Know

CVE-2025-29927 -

On March 21st, 2025, the Next.js maintainers announced a new authorization bypass vulnerability – CVE-2025-29927. This vulnerability can be easily exploited to achieve authorization bypass. In some cases – exploitation of the vulnerability can also lead to cache poisoning and denial of service.

Which versions of Next.js are affected?

Next.js 15.x – from version 15.0.0 up to and including 15.2.2.

Next.js 14.x – from version 14.0.0 up to and including 14.2.24.

Earlier Next.js versions – from version 11.1.4 up to and including 13.5.6.

Attack scenarios for CVE-2025-29927

In order for the vulnerability to be exploited at all, the victim Next.js server must use a Next.js Middleware. This consists of including a middleware.js or middleware.ts file ( _middleware.js or _middleware.ts  for older versions of Next.js). This file defines and exports the middleware function that holds the logic run when each HTTP request is received.

Authorization bypass

This is the most likely exploitation scenario for CVE-2025-29927.

This scenario is relevant when the victim Next.js server uses the Middleware feature to perform authorization (and the underlying application doesn’t use any other authorization layers).

Authorization middleware scenario without CVE-2025-29927 exploitation

Authorization middleware scenario with CVE-2025-29927 exploitation

Denial of service via cache poisoning

Next.js middleware can also help with localizing websites. For example, the middleware can automatically redirect users based on their location—say, adding /en for English speakers or /fr for French visitors. If someone exploits CVE-2025-29927 and bypasses the middleware that performs these redirects – instead of landing on a localized page, they will land on the website root (/), for which the developers never built a page. The result? A 404 error or a 500 server error, depending on the configuration.

If the site uses a CDN or another caching layer, these error responses can be stored and served to future visitors. Once cached, legitimate users might see broken pages globally. This creates a self-inflicted outage, crippling availability without changing a single line of code.

Redirector middleware scenario without CVE-2025-29927 exploitation

 

Redirector middleware scenario with CVE-2025-29927 exploitation

 

Understanding Next.js Middleware

Next.js middleware is a powerful feature introduced in Next.js v12 that allows developers to execute code before a request is completed. Operating on the edge, closer to the user than traditional server-side code, middleware can modify response headers, rewrite or redirect requests, and most importantly- implement authentication and authorization checks.

Middleware in Next.js runs before rendering and can be configured to execute on specific paths through matcher configurations.

A few example use-cases for Next.js middleware are:

  • Verifying authentication tokens
  • Implementing role-based access control
  • Redirecting unauthenticated users

A typical Next.js middleware implementation that performs authentication might look like this:

 

 import { NextResponse } from 'next/server'
 import type { NextRequest } from 'next/server'

 export function middleware(request: NextRequest) {
   // Get the user token from the cookies
   const token = request.cookies.get('token').value
  
   // Validate the user is authenticated
   const isAuthenticated = validateToken(token)
  
   // If not authenticated, redirect to login
   if (!isAuthenticated) {
     return NextResponse.redirect(new URL('/login', request.url))
   }
  
   // Continue to protected route if authenticated
   return NextResponse.next()
 }

 // Configure which routes use this middleware
 export const config = {
   matcher: ['/dashboard/:path*', '/settings/:path*'],
 }
 
Copy Command

CVE-2025-29927 technical analysis

CVE-2025-29927 exposes a critical flaw in how Next.js middleware processes certain types of requests, leading to potential authentication and authorization bypasses.

This vulnerability affects applications using middleware for access control in certain configurations.

The vulnerability stems from the inconsistent handling by Next.js of the custom x-middleware-subrequest headers. When this header is included in requests to protected routes, Next.js incorrectly allows the request to bypass middleware execution entirely. The header forces the Next.js runtime to skip the middleware evaluation phase while still processing the underlying route handler.

To exploit this vulnerability, an attacker simply needs to add the x-middleware-subrequest header to their HTTP requests when accessing protected resources. For example, a request to  /api/admin/users that would normally be blocked by middleware authorization checks will be processed normally when this header is present. The server processes the request as though middleware has already run and approved it, creating a complete security bypass. This header manipulation can be easily implemented using browser developer tools, curl commands, or simple scripts.

The vulnerable code on the latest version that is vulnerable (v15.2.2) is as follows:


 export const run = withTaggedErrors(async function runWithTaggedErrors(params) {
 const runtime = await getRuntimeContext(params)
 const subreq = params.request.headers[`x-middleware-subrequest`]        [1]
 const subrequests = typeof subreq === 'string' ? subreq.split(':') : [] [2]

 const MAX_RECURSION_DEPTH = 5
 const depth = subrequests.reduce(                                       [3]
  (acc, curr) => (curr === params.name ? acc + 1 : acc),
  0
 )

 if (depth >= MAX_RECURSION_DEPTH) {                                     [4]
  return {
     waitUntil: Promise.resolve(),
     response: new runtime.context.Response(null, {
       headers: {
         'x-middleware-next': '1',
       },
     }),
   }
 }
 
Copy Command

The x-middleware-subrequest header is taken from the request on [1].
It’s then split using the : delimiter on [2], and ran through a reduce function that counts how many items in this array (subrequests) match the middleware filename on [3].
If this number is equal or more than MAX_RECURSION_DEPTH (which is 5) on [4], it then bypasses the functionality of the middleware and redirects to its route.

Attack header possible values

As explained before, the vulnerable header name is  x-middleware-subrequest. The value assigned to it depends on Next.js because it is set according to the value of middlewareInfo.name which is essentially the path to the middleware.js or middleware.ts file.

Before version 12.2, the middleware file was actually named _middleware.js/_middleware.ts and could have been located at any level of the subdirectory we’re trying to access. In our case, we’re trying to access /admin/dashboard which means middlewareInfo.name could have been pages/_middleware or pages/admin/_middleware. Had we set dashboard to be a directory with an index.js file, it could have also been pages/admin/dashboard/_middleware.

For example, if we had been using a Next.js version prior to 12.2 with our PoC code, we would have needed to move middleware.js to the pages directory and rename it _middleware.js, and our “malicious” HTTP request would be:


 GET /admin/dashboard HTTP/1.1
 x-middleware-subrequest: pages/_middleware
 
Copy Command

Since version 12.2 and until version 13, the middleware file has to exist at the root of the project and has to be named middleware.js/middleware.ts. So for attacking these versions of Next.js, the payload for the header would just be middleware – and we know for a fact that it is in the root directory.

If we had been using a Next.js version between versions 12.2 and 13, our “malicious” request would change as follows:


 GET /admin/dashboard HTTP/1.1
 x-middleware-subrequest: middleware
 
Copy Command

From version 13 of Next.js and onwards, the recursion check we saw before was implemented – which means that an attacker would have to set the malicious header to be middleware:middleware:middleware:middleware:middleware, to simulate 5 levels of recursion.

Since our PoC is on this version, this is a snippet from the request we used:


 GET /admin/dashboard HTTP/1.1
 x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
 
Copy Command

Keep in mind that at all stages, the Middleware code could have been in a src directory – which would mean prepending src to the values presented above would be necessary for exploiting. For example, if we had put our PoC code in a src directory, our payload would have needed to be:


 GET /admin/dashboard HTTP/1.1
 x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware.
 
Copy Command

Exploiting CVE-2025-29927

As always, it’s best to see a full exploitation of the vulnerability to understand which Next.js instances would be vulnerable.

We set up our own PoC website with the following working tree:

├── middleware.js
├── package-lock.json
├── package.json
└── pages
├── admin
│   └── dashboard.js
└── index.js

First of all, our login page:

This is what happens when a non-admin user attempts to log in:

And this is the admin dashboard at /admin/dashboard with the correct credentials:

Moving to the exploit – first, let’s attempt to send a GET request to /admin/dashboard without the malicious header:

We get a 401 unauthorized response, since our middleware kicks in and sees that this isn’t an admin account:

However, let’s try to do the same thing again with the x-middleware-subrequest header:

And we get back a 200 OK response!

Using the web preview, we can also see that we’ve received the document before:

Resolving CVE-2025-29927

Version Upgrade

The best way to resolve CVE-2025-29927 is to upgrade your version of Next.js to one of the fixed versions –

  • 15.2.3
  • 14.2.25

Make sure to identify any versions that might be at risk, from 11.1.4 up to and including 13.5.6, 14.2.24, and 15.2.2, and update them to this newly fixed version.

Blocking the vulnerable header in the Web Server

If upgrading is not an option, the vulnerability can be mitigated by instructing your web server to strip the `x-middleware-subrequest` from incoming requests –

In Apache, add the following directive to your .htaccess file (mod_headers must be installed and enabled) –

 <IfModule mod_headers.c>
   RequestHeader unset x-middleware-subrequest
 </IfModule>

In NGINX, edit your nginx.conf file and add the following proxy_set_header directive to your server block –

 proxy_set_header x-middleware-subrequest "";

For example –

 server {
   listen 80;
   server_name your_domain.com;
   location / {
     proxy_set_header x-middleware-subrequest "";
   }
 }

In Express.js, add the following directive to your JavaScript source code –

 // Middleware to remove the x-middleware-subrequest header
 app.use((req, res, next) => {
   delete req.headers['x-middleware-subrequest'];
   next();
 });

Blocking the vulnerable header with a WAF

If upgrading is not an option, the vulnerability can be mitigated by using a Web Application Firewall to block requests that contain the x-middleware-subrequest` HTTP Header.

Resolving CVE-2025-29927 with JFrog Xray and JFrog Advanced Security

As always, JFrog Security Essentials (Xray) can be used to identify every occurrence of Next.js across your entire codebase and compiled  artifacts, including Docker containers, repository packages, and even standalone binaries.

Additionally, JFrog Advanced Security has been updated with a Contextual Analysis scanner that automatically checks whether your Next.js deployment is truly vulnerable to CVE-2025-29927 by checking whether a Next.js Middleware is used.


JFrog Platform: JFrog Contextual Analysis for Next.js’s CVE-2025-29927 (Click image for full-size)

Check out the JFrog Security Research center for the more information about the latest CVEs and vulnerabilities and fixes.