CVE-2025-29927 漏洞複現
這篇紀錄 Next.js CVE-2025-29927 的漏洞原理與受控本機 PoC,說明 x-middleware-subrequest header 為何會造成 middleware 授權繞過,以及官方如何修補。
結論
Next.js 在 v11 到 v15.2.2 中,對 x-middleware-subrequest header 採取信任策略。然而由於缺乏來源驗證,攻擊者可偽造該 header 來繞過授權邏輯,構成嚴重的權限繞過漏洞(CVE-2025-29927)。
自 v15.2.3 起,官方改為建立唯一的 middleware session ID,並比對該 ID 來判斷是否為內部請求,有效解決此問題。
漏洞簡介
| 項目 | 內容 |
|---|---|
| 漏洞編號 | CVE-2025-29927 |
| 漏洞類型 | 授權繞過 |
| 影響範圍 | Next.js v11.1.4 ~ v15.2.2(含) |
| CVSS 3.X | 9.1 Critical |
CVSS 指標
| Exploitability Metric | Value |
|---|---|
| AV | Network |
| AC | Low |
| PR | None |
| UI | None |
| Impact Metric | Value |
|---|---|
| S | Unchanged |
| C | High |
| I | High |
| A | None |
當 Next.js 使用 Middleware 處理授權邏輯時,攻擊者可透過特殊標頭 X-Middleware-Subrequest 繞過中介軟體的授權邏輯,進而未經授權訪問受保護的頁面。
發現者與時間線
- 發現者:Akamai 研究人員。
- 回報時間:2025 年 3 月 14 日首度通報給 Next.js 官方開發團隊。
- 修補版本:Next.js 團隊於 2025 年 4 月 10 日釋出修補版本。
- 公告時間:2025 年 4 月 16 日公告漏洞細節與 CVE 編號。
漏洞原理和利用方法
Next.js 使用內部特殊標頭 x-middleware-subrequest 來識別內部請求,例如 React Server Components 或 App Router 中的子請求。
若攻擊者在外部請求中加入此標頭,Next.js 可能錯誤地認定其為內部請求,跳過 middleware 的驗證邏輯。
根本原因是 Next.js 在處理子請求中間件機制時存在設計缺陷。
內部子請求識別方式
當 middleware 需要向內部路由發送請求,例如抓取資料或執行驗證時,Next.js 會自動加入 x-middleware-subrequest 標頭,用來標示這是內部請求,以避免 middleware 重複執行造成無限循環。
缺乏來源驗證
漏洞關鍵在於 Next.js 並未對這個標頭的來源進行嚴格驗證。這導致外部請求如果攜帶該標頭,也會被誤認為是內部子請求。
中間件邏輯問題
只要 Next.js 偵測到請求中有 x-middleware-subrequest 標頭,就可能略過對該請求的 middleware 處理,直接將其導向對應路由或 API。
繞過授權檢查
攻擊者只需手動添加這個特殊標頭,即可繞過原本由 middleware 執行的授權驗證,直接存取應該受保護的資源。
漏洞復現步驟
以下內容僅作為受控本機環境中的漏洞學習與研究筆記。
系統環境
- Windows 10
- Node.js v22.14.0
- Next.js v15.2.2
流程概覽
- 下載 Node.js。
- 建立漏洞專案。
- 製作 middleware 腳本。
- 設定
next.config.mjs。 - 建立
run.js。 - 啟動 server。
- 傳送 payload,觀察 middleware bypass 行為。
下載 Node.js
進入 Node.js 官網並下載 Node.js v22.14.0。完成後可至 cmd 驗證是否成功:
1 | node -v |
都有出現對應版本編號即可。
建立漏洞專案
建立專門針對漏洞 PoC 的最小環境 vuln_nextjs_calc。
1 | cd C:\Users\testUser\Desktop |
設定執行環境,使用有漏洞的 next@15.2.2:
1 | cd vuln_nextjs_calc |
看到 Critical 就是指 CVE-2025-29927。
套件說明:
next@15.2.2:內含 CVE-2025-29927 漏洞。react、react-dom:執行 Next.js 必要 package。
製作 middleware.js
建立 vuln_nextjs_calc/middleware.js,此程式用於在請求到達頁面前先做檢查,例如:
- 是否已登入?
- 是否有權限訪問某頁?
- 是否來自內部來源?
1 | import { NextResponse } from 'next/server' |
簡單來說,如果有抓到 x-middleware-subrequest 則通行請求;否則拒絕授權請求。最後透過 matcher 指定 /protected/* 都會被 middleware 攔截。
為什麼是 x-middleware-subrequest
因為這個標頭是 Next.js 自己內部產生的,一般用戶端並不會產生。
Next.js 在處理內部子請求時會自動加上這個標頭。由於這些請求其實來自 Next.js 自己的核心模組,所以 Next.js 預設信任這個標頭,漏洞也因此產生。
若我們知道它會依照 header 進行判斷,就能在 curl 時加上這個 header 觀察 bypass:
1 | curl "http://localhost:3000/protected/run?cmd=calc" -H "X-Middleware-Subrequest: 1" |
為什麼是 /protected
本次 PoC 將漏洞入口放置於 /protected/,模擬現實系統中將內部功能藏於「看似有授權,但實際驗證不足」的路徑下。
相較於高敏感度的 /admin/,此類路徑往往因為開發者認為不容易猜中而疏於設防,是授權繞過的熱門目標。
建立 run.js
新建 run.js 於 pages/protected/,模擬真實系統中「僅供內部或管理員操作的命令執行功能」。
1 | import { exec } from 'child_process' |
啟動 server 並執行 payload
啟動 server:
1 | npm run dev |
執行 curl 並加上 header:
1 | curl "http://localhost:3000/protected/run?cmd=calc" -H "X-Middleware-Subrequest: 1" |
也可以在受控本機測試其他 payload:
1 | curl "http://localhost:3000/protected/run?cmd=notepad" -H "X-Middleware-Subrequest: 1" |
整個攻擊流程就完成了。
Patch / Workaround
問題本質 Recap
Next.js 錯誤地信任 header,導致攻擊者只要加上這個 header,就能繞過 middleware 的驗證。
官方修復
根據 Next.js GitHub 官方提交紀錄 Update middleware request header (#77201),官方在 commit 中將對 x-middleware-subrequest 的信任邏輯,改為使用 isInternalRequest() 進行判斷,從而防止外部請求偽造 header 繞過中介層驗證。
統整更動
| 分析項目 | 原本的做法 | 導致的問題 | 修補後的做法 |
|---|---|---|---|
| 是否為內部請求 | 只要請求帶有 x-middleware-subrequest 就視為內部請求 |
攻擊者可以用 curl 加上這個標頭騙過 middleware,繞過授權 | 驗證該請求是否帶有正確 session 的唯一 ID,才信任它是內部請求 |
| 判斷邏輯位置 | 沒有驗證來源,只靠單一 header 判斷 | 外部使用者可偽造 header,跳過中間件邏輯並執行敏感操作 | 在核心程式碼中加入 session 追蹤與 header 過濾,清除不合法 header |
| 繞過途徑 | curl "http://host" -H "X-Middleware-Subrequest: 1" |
沒有比對內部 request session ID,任何人都可能成功繞過驗證 | 必須同時帶有 Next.js 內部塞入的 x-middleware-subrequest-id,並且與 global session 一致,否則直接刪除 header |
資料來源
- GitHub / Next.js 官方
- NVD 漏洞訊息
- Censys 漏洞訊息
- Vercel 漏洞追蹤
- JFrog 漏洞原理
- Title: CVE-2025-29927 漏洞複現
- Author: NPCMike
- Created at : 2025-04-23 00:00:00
- Updated at : 2026-05-13 16:49:36
- Link: https://npcmike.github.io/2025/04/23/CVE-2025-29927/
- License: This work is licensed under CC BY-NC-SA 4.0.