如何檢查 Node.js 是否受 CVE-2026-111497 影響並修補 Brotli RCE
هل إصدار Node.js لديك مهدد بثغرة Brotli RCE؟ تحقق في دقيقتين
Node.js Brotli RCE 漏洞 CVE-2026-111497 已有活躍利用,22.x、24.x、26.x 的修補版本下限分別為 22.23.4、24.22.1、26.12.1。
文章把版本檢查與實際 Brotli 解碼路徑分開,並比較多種 Node.js 框架及客戶端的行為,呈現判斷漏洞暴露面所需的兩個條件。
你的 Node.js 版本是否受到 Brotli RCE 漏洞威脅?兩分鐘內檢查
立即執行此命令。如果你的版本低於下表所列的最低版本,Node.js Brotli 函式庫的遠端程式碼執行(RCE)漏洞(CVE-2026-111497)便會影響你,而且攻擊者已在利用此漏洞。
node -v
| 版本分支 | 受影響版本 | 修復版本由此開始 | 最新版本(2026 年 11 月 5 日) |
|---|---|---|---|
| 26.x | 低於 26.12.1 | 26.12.1 | 26.13.0 |
| 24.x | 低於 24.22.1 | 24.22.1 | 24.22.2 |
| 22.x | 低於 22.23.4 | 22.23.4 | 22.23.4 |
| 25.x, 20.x, 較舊版本 | 已結束支援:未修補,亦未評估 | 沒有可用修復版本 | 升級至 24 或 26 |
如要透過第二項指標確認,你可以直接查詢可執行檔:
node -p "require('node:zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"
此更新加入了這個常數。我們已在三個受支援版本分支的九個 macOS 官方建置版本上執行該命令:每個已修補版本均出現 -17,而所有較舊版本均出現 undefined。不過,應先以 node -v 為準,因為部分採用回移植修補程式的 Linux 發行版可能不會加入這個常數。
忽略 process.versions.brotli;在 24.21.0 和 24.22.1 中,它均回傳 1.2.0;在 22.23.3 和 22.23.4 中,它均回傳 1.1.0。Node.js 團隊合併修復時沒有更改對外公佈的版本號,因此這個欄位無法顯示你的系統是否已取得修補程式。
快速摘要(TL;DR)
| 問題 | 答案 |
|---|---|
| 這是甚麼漏洞? | Node.js 內置 Brotli 解碼器中的越界寫入漏洞,亦稱為 Node2Shell 或 HTTP2Shell |
| 影響 | 應用程式崩潰、記憶體資料外洩,或遠端程式碼執行 |
| 嚴重程度 | 根據 Node.js,屬高危;根據 NVD,屬嚴重,評分為 9.8(CVSS 3.1) |
| 目前是否有人利用此漏洞? | 是。CISA 已於 2026 年 10 月 27 日將此漏洞列入已知遭利用漏洞目錄 |
| 是否需要登入? | 不需要,根據 NVD 評分向量及 Akamai 的分析 |
| 哪些人面臨風險? | 會解碼不可信 Brotli 資料的應用程式,例如 Express 5 請求本文、fetch() 回應,以及直接呼叫 node:zlib 函式庫的程式
|
| 解決方法 | 升級執行環境、重建容器映像,並重新啟動程序 |
| 有沒有替代方法? | 安全公告沒有提及任何替代方法。下文的臨時措施可縮小受攻擊面,但無法涵蓋所有情況 |
ELLIO 表示,截至 10 月 26 日,其感測器已偵測到漏洞利用流量,距離修復程式推出僅五天。被截獲的惡意載荷針對 x86-64 架構上的 Node.js 24.22.0。雖然該載荷的最後階段在 ELLIO 測試期間執行失敗,但該公司確認,同一段程式碼無須修改,便可在官方 24.22.0 版本上執行。CISA 給予美國聯邦機構截至 11 月 10 日採取行動的期限,並將勒索軟件的使用情況評為「未知」。Akamai 的遙測數據顯示,截至 10 月 26 日,仍有 61% 的網絡運行受影響版本。
Node2Shell 漏洞詳解:Brotli 缺陷如何運作?
Node2Shell 是 Node.js 執行環境內置 Brotli 解碼器中的越界寫入錯誤。損毀的壓縮資料流會令解碼器寫入超出一個 8 位元組內部緩衝區的末端,導致程序記憶體受損。這可能令應用程式崩潰、洩漏記憶體資料,或讓攻擊者在你的伺服器上執行其控制的程式碼。
根本原因是錯誤狀態分類有誤:無效的區塊切換被解讀為「需要更多輸入」,而不是「資料已損毀」,令串流解碼器繼續將位元組附加到該小型緩衝區。
問題源於 Google 的 Brotli 函式庫,影響 1.0.3 至 1.2.0 版本,因此並非只限於 Node.js。Node.js 已透過合併上游的程式碼修補 0ed4268a,修正其所用版本,並納入 24.22.1 版本及相應的同系列版本。OpenAI Codex 的兩名安全研究員 Khai Tran 和 Sylvie Meyer 通報了這個漏洞。
你的相依套件掃描工具無法偵測這項漏洞,因為解碼器直接內置於執行環境中,而非獨立套件。例如,在未修補的 Node.js 24.15.0 上執行時,npm install 命令顯示我們以 Express 5 建立的示範專案有 0 個安全漏洞。
哪些用戶面臨風險?
執行環境受感染只是面臨風險的其中一個條件,另一個條件是存在一條會將不受信任的 Brotli 資料傳送至解碼器的路徑。我們在 Node.js 24.22.1 上測試了每條路徑:傳送包含無效但無害文字(文字 not-valid-brotli)的請求本文,並附上 Content-Encoding: br 標頭;亦向每個用戶端提供有效的 Brotli 資料。
| 路徑 | 測試版本 | 是否會執行解碼器? | 觀察到的結果 |
|---|---|---|---|
Express 5 express.json()
|
5.3.0 (body-parser 2.4.0) | 是,預設會 | 400,「Decompression failed」 |
Express 4 express.json()
|
4.22.3 (body-parser 1.20.9) | 否 | 415,不支援的編碼 |
Koa @koa/bodyparser |
6.1.0 | 是,預設會 | 500,記錄中出現 BrotliDecoder 錯誤 |
Fastify 配合 @fastify/compress |
9.3.0 | 是,註冊外掛後便會 | 400,FST_CP_ERR_INVALID_CONTENT |
| Fastify 不配合外掛 | 5.12.8 | 否 | 400,無效的 JSON 資料 |
直接使用 node:http 伺服器或 http.get |
24.22.1 | 否 | 原始位元組會原樣傳遞 |
內置的 fetch() 函數 |
24.22.1 | 是,一定會 | 回應已解碼 |
| axios、got、node-fetch | 1.21.0, 16.2.0, 3.3.2 | 是,預設會 | 回應已解碼 |
zlib.brotliDecompress*, createBrotliDecompress
|
任何版本 | 是 | 這就是解碼器 API |
有兩個結果值得仔細檢查。第一,fetch() 函數即使在請求附有 Accept-Encoding: identity 標頭時,仍會解碼 Brotli,因為它會依據回應標頭,而非你具體提出的要求。這表示應用程式呼叫的任何外部伺服器都可能讓解碼器處理資料,令 webhook 測試工具、連結預覽或 URL 匯入功能面臨風險。第二,單憑 400 錯誤回應並不能證明任何事;Express 5 和未安裝外掛的 Fastify 都會回傳 400,但只有 Express 5 實際執行了解碼器。因此,請一併檢查錯誤訊息。
你可以使用以下三條指令,檢查有哪些路徑面臨風險:
# Direct decoder use
grep -rnE "brotliDecompress|createBrotliDecompress" src/
# Parsers that decode request bodies
npm ls express body-parser @koa/bodyparser @fastify/compress
# Base images and pinned versions
grep -rnE "^FROM .*node" --include='Dockerfile*' .
請記住,只要新增一次對 fetch() 函數的呼叫,這些判斷便可能完全改變。因此,即使目前「沒有面臨風險」,也代表你必須立即套用修補程式。
如何修補 CVE-2026-111497 漏洞
請升級至所用版本分支的最新版本,而非只升級至最低修補版本。截至 11 月 5 日,以下來源均已提供修補版本:
| 安裝方式 | 所需操作 |
|---|---|
| nvm | nvm install 24 && nvm alias default 24 |
| Homebrew |
brew upgrade node(或 node@24、node@22) |
| Docker |
FROM node:24.22.2-slim,然後執行 docker build --pull
|
| Linux 發行版套件 | 請按照所用發行版的安全公告操作,因為修補程式可能會以較舊的版本號回溯套用 |
| CI | 更新 .nvmrc、engines 和 node-version,然後重新建置 |
| 無伺服器雲端環境 | 從已部署的函數記錄 process.version 的值以作確認;不要假設平台已自動更新 |
接著,處理兩個常見的疏忽:
- 重新啟動所有項目:正在執行的程序會將舊的可執行檔保留在記憶體中,因此只升級磁碟上的檔案並不會改變任何事,必須透過 pm2、systemd 或容器管理系統等工具重新啟動程序。
- 重新建置已部署的項目:舊的容器映像仍會保留舊的執行環境,而以不可變識別碼固定版本的映像需要進行映像安全掃描,因為版本標籤無法反映實際情況。
最後,請在已部署的容器內執行本文開頭提到的檢查,然後在 CI 執行器和開發人員的電腦上執行。若要查看每個版本分支最新的安全版本:
curl -s https://nodejs.org/dist/index.json | jq -r '[.[] | select(.security == true and (.version | test("^v(22|24|26)\\.")))] | group_by(.version | split(".")[0]) | .[] | max_by(.date) | "\(.version) \(.date)"'
你仍在使用 20 或 25 版本嗎?目前沒有任何已修補版本可供你使用。請參閲 Node.js 20 支援終止計劃,並立即升級。
如果今天未能修補:Node.js Brotli 漏洞的緩解措施
這些步驟可以為你爭取一些時間,但沒有任何一項可以取代實際升級。
-
在網絡邊界拒絕
br編碼:在代理伺服器或負載平衡器封鎖Content-Encoding: br標頭,並確保不區分大小寫,且能在gzip, br等清單中識別它。 - 在應用程式中拒絕編碼:在請求文字解析器之前加入這段程式碼;我們在 Express 5 上測試時,它回應了 415 狀態碼。
app.use((req, res, next) => {
const encoding = req.headers['content-encoding'] || '';
if (/\bbr\b/i.test(encoding)) return res.status(415).end();
next();
});
-
停用自動解壓縮:設定
express.json({ inflate: false })後,相同請求會得到 415 狀態碼。不過,它也會拒絕以 gzip 壓縮的請求,因此請先確認用戶端是否相容。 -
控制傳出的回應:axios 支援
decompress: false選項;我們測試時,位元組保持未解碼狀態。至於函式fetch(),則沒有提供停用解壓縮的標準選項,因此必須透過允許清單和輸出流量規則,限制它可以連線的主機。 - 減低影響範圍:將 Node.js 服務隔離在不同環境中,並限制對當機記憶體傾印檔案的存取權限。ELLIO 指出,應用程式當機可能會令檔案中的敏感記憶體資料外洩。
密切留意 ELLIO 最先觀察到的情況:以 Brotli 編碼的請求文字突然大量湧入,以找出正在解碼這些內容的主機。因此,如果 JSON API 出現帶有 Content-Encoding: br 的異常流量,或程序當機次數突然上升,便應立即調查。
升級後確認 API 完整性:讓 AI Agent 負責處理
執行環境版本轉換可能會改變 TLS、DNS 和 HTTP 的行為,而 10 月份的更新同時涵蓋這三方面。不要手動比較差異;讓你的編碼 Agent 在升級前後執行 Apidog CLI,再提供變更報告。
npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com # pick your agent when prompted
把這段提示詞交給你的編碼 Agent:
Run Apidog test suite <id> in project <id> against staging and save the
results to reports/before. After I upgrade Node.js, add a test case for
POST /orders that sends the plain text "not-valid-brotli" with
Content-Encoding: br, asserts a 4xx status, then checks GET /health
returns 200. Rerun the suite to reports/after and list every request
whose result changed.
Agent 將執行以下命令:
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/before
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <id> --file case.json
apidog run --test-case <caseId> --project <id> -e <envId> -r cli,json
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/after
這個額外測試案例是系統完整性檢查,而不是漏洞利用攻擊;請求內容只是普通文字。在我們的測試中,受影響版本和已修補版本都因相同的填充錯誤而失敗。即使如此,這項檢查仍揭示了真實的錯誤處理漏洞:測試用的 Koa 伺服器因未處理解碼錯誤而回應 500,但任何公開 API 都應回應 4xx 類別的狀態碼。請只在預備環境執行這項測試。
執行命令參考列出所有可用選項,而 CI/CD 指南則説明如何將 JUnit 測試執行整合至自動部署流程。Apidog 免費方案最多支援 4 位用戶。
即將到來的 11 月 11 日為何重要
Node.js 專案早前預告,將於 2026 年 11 月 11 日或之後不久,為 26.x、24.x 及 22.x 版本系列推出即將發佈的安全更新,當中的最高嚴重程度評級將再次為「高」。CVE 編號尚未公開。我們的 11 月版本指南説明如何為此作好準備。
現在就修補 Brotli 漏洞,不要押後並與即將推出的更新一併處理;漏洞的詳細資訊已公開,而且目前已有活躍的漏洞利用活動。你今星期進行的升級,也是為下一次升級作實戰演練:同樣的資產清點、同樣的映像檔重建、同樣的測試套件。過往的 PHP2Shell 和 React2Shell 等漏洞,也完全遵循同一模式。
常見問題 (FAQ)
CVE-2026-111497 目前是否正遭利用? 是。CISA 於 2026 年 10 月 27 日將其加入已知遭利用漏洞目錄,列於 Google Brotli 項目下;ELLIO 則在 10 月 26 日前已記錄到活躍的利用嘗試。
它的評級是高危還是嚴重? 兩種評級都正確且符合實際情況:Node.js 將其評為高危,NVD 資料庫則根據 CVSS 3.1 將其評為嚴重,評分為 9.8;Google 根據 CVSS 4.0 給予 9.2 分。制定計劃時,應以漏洞已遭利用這一事實為準。
我使用 Express 4,是否安全? 傳入的請求內容不會在你的應用程式中傳到解碼器,但對 fetch() 和 axios 的呼叫,以及直接使用程式庫 node:zlib,仍會傳到解碼器。此外,同一版本亦修正了另外九個 CVE 漏洞,因此無論如何都應升級。
Node.js 20 版本是否受影響? Node.js 專案不會評估已結束支援的版本系列,也不會為其提供修補程式。請將 20.x 和 25.x 視為未修補且未經評估的版本,並盡快升級至受支援的版本。
除了 Node.js,其他系統也會受此漏洞影響嗎? 會。GitHub 上的安全公告涵蓋 PyPI 上的套件 brotli 和 brotlicffi;開發人員亦宣佈已為 Bun 1.4.4 和 .NET 推出修正。請分別更新每個解碼器,因為升級 Node.js 只會更新其內置的版本。
來源:DEV Community · dev.to


