CVE-2025-29927 Next.js 中间件权限绕过漏洞¶
漏洞描述¶
Nextjs是一个使用react作为前端框架底层的支持SSR(请求时渲染)、SSG(构建时渲染)等技术的全栈框架,在2022年的服务端框架中排名第一。
它的优点非常明显,既支持react的虚拟dom形式快捷完成开发,又支持访问即可看到完整内容,友好的SEO/浏览器直出形式。结合了静态分离和服务器渲染的双重优势。
CVE-2025-29927 是一个存在于 Next.js 框架中的关键安全漏洞。该漏洞允许攻击者通过伪造或篡改 x-middleware-subrequest 请求头,绕过中间件(Middleware)的安全检查,从而访问到原本受保护的路由或 API,进而导致授权绕过(Authorization Bypass)以及潜在的更深层次安全风险。
影响版本¶
根据官方与社区披露,受影响的版本范围及对应修复版本如下:
- Next.js 11.1.4 ~ 13.5.6:未修补版本
- Next.js 14.x:在 14.2.25 之前均受影响
- Next.js 15.x:在 15.2.3 之前均受影响
环境配置¶
- vulhub
- Docker-compose

漏洞复现¶
- 手动复现

在没有登陆时,访问根目录会跳转到login路由
添加header


绕过登陆,直接未授权访问
- nuciel
id: CVE-2025-29927-HEADLESS
info:
name: Next.js Middleware Authorization Bypass
author: ademking
severity: critical
description: |
A critical vulnerability in Next.js middleware allows attackers to bypass authorization checks by manipulating the x-middleware-subrequest header. This flaw affects Next.js versions prior to 14.2.25 and 15.2.3, potentially granting unauthorized access to sensitive resources.
reference:
- https://github.com/advisories/GHSA-f82v-jwr5-mffw
- https://nvd.nist.gov/vuln/detail/CVE-2025-29927
- https://www.tenable.com/cve/CVE-2025-29927
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
cvss-score: 9.1
cve-id: CVE-2025-29927
cwe-id: CWE-285
metadata:
vendor: vercel
product: Next.js
framework: node.js
tags: cve,cve2025,headless,nextjs
headless:
- steps:
- args:
url: "{{BaseURL}}"
action: navigate
- action: waitstable
- action: script
name: nextjs_version
args:
code: |
() => {
if (!window.next || !window.next.version) {
return "";
}
return window.next.version;
}
extractors:
- type: dsl
part: nextjs_version
dsl:
- '"Vulnerable Next.js => " + nextjs_version'
matchers:
- type: dsl
dsl:
- "compare_versions(nextjs_version, '>= 11.1.4', '<= 13.5.6')"
- "compare_versions(nextjs_version, '> 14.0.0', '< 14.2.25')"
- "compare_versions(nextjs_version, '> 15.0.0', '< 15.2.3')"
condition: or
# digest: 4a0a00473045022100e7ef01315b5c9dff2e5567ad1421f5cf95ccaa62554a094e5faada3fe08261a10220611dab02751e9a58d17176f3632bd8a638191fc08abc6b7453a34abb9de3a5a0:922c64590222798bb761d5b6d8e72950
漏洞原理¶
Next.js 的中间件(Middleware)设计用于处理全局请求逻辑(如身份验证、请求拦截,假设开发者编写了一个身份验证中间件,其功能是:当用户访问受保护资源时,中间件需向校验 API 发送请求以验证用户权限(如查询数据库或调用外部服务)。
由于 Next.js 是「全栈框架」,所有请求(包括中间件内部发起的 API 请求)均会再次经过中间件本身。这导致以下递归流程:
最终引发无限递归,导致服务崩溃或响应超时。
为打破递归循环,Next.js 引入了两项机制:
- 请求标记: 中间件内部发起的请求会自动添加
x-middleware-subrequest头,其值按层级递增(如middleware:middleware:middleware)。 - 递归终止条件: 当检测到
x-middleware-subrequest头中包含当前中间件标识(如middleware)的次数超过阈值(默认5次),中间件直接返回空响应,终止递归
主要逻辑在这里 https://github.com/vercel/next.js/blob/v15.2.2/packages/next/src/server/web/sandbox/sandbox.ts
export const run = withTaggedErrors(async function runWithTaggedErrors(params) {
const runtime = await getRuntimeContext(params)
const subreq = params.request.headers[`x-middleware-subrequest`] //
const subrequests = typeof subreq === 'string' ? subreq.split(':') : []
const MAX_RECURSION_DEPTH = 5
const depth = subrequests.reduce(
(acc, curr) => (curr === params.name ? acc + 1 : acc),
0
)
if (depth >= MAX_RECURSION_DEPTH) {
return {
waitUntil: Promise.resolve(),
response: new runtime.context.Response(null, {
headers: {
'x-middleware-next': '1',
},
}),
}
}
当请求头中包含 x-middleware-subrequest 时,中间件会将其值按 : 分割为数组 subrequests,并检查是否包含当前中间件的 name(即中间件文件路径)
若 subrequests 中包含当前中间件名称,则 depth 自增。当 depth ≥ 5 时,中间件返回空响应并停止处理。
所以漏洞的利用思路是,只要在发送给next.js的请求中增加一个头**x-middleware-subrequest:**,让其循环5次中间件文件路径,就可以绕过next.js的中间件。如果开发者将校验用户身份的逻辑放在中间件里,就将导致认证绕过漏洞。
中间件文件路径是可以预测的
- 旧版本(≤12.2):中间件文件必须命名为
_middleware.ts并放置在pages/目录或其子目录下。例如,若中间件位于/pages/dashboard/_middleware.ts,则middlewareInfo.name为pages/dashboard/_middleware,攻击者只需在请求头中设置x-middleware-subrequest: pages/dashboard/_middleware即可绕过。 - 新版本(≥12.2):中间件文件更名为
middleware.ts,位于src/或根目录。此时,攻击者只需设置x-middleware-subrequest: middleware或x-middleware-subrequest: src/middleware即可绕过。
所以最终payload为
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
或者
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware
修复建议¶
升级 Next.js 版本
- ≥15.2.3(15.x)
- ≥14.2.25(14.x)
给中间件的白名单请求头现在改成了一个随机的 8 字节 ID ,标识中间件子请求的来源,被添加到请求头 x-middleware-subrequest-id 。如果请求头中的 x-middleware-subrequest-id 与全局存储的 ID 不匹配,则删除 x-middleware-subrequest 请求头。此更改确保了只有来自相同会话的子请求才会被视为中间件子请求。

