跳到正文
DEV Community· Roobia·· 33 分鐘前精選AI 評分84

如何在 2 分鐘內檢查 Node.js 版本是否受 Brotli RCE 漏洞 CVE-2026-111497 影響

¿Tu versión de Node.js es vulnerable al RCE de Brotli? Compruébalo en 2 minutos

AI 導讀

作者整理了檢查 Node.js 是否受 Brotli 解碼器 RCE 漏洞 CVE-2026-111497 影響的方法,並列出 22.x、24.x、26.x 的修補門檻,分別為 22.23.4、24.22.1 和 26.12.1。

推薦理由

文章對照 `node -v`、Brotli 常數及 `process.versions.brotli` 的檢查限制,並整理更新 runtime、重建容器映像和重啟程序的修補流程。

正文 · 繁體中文

立即執行。如果你的版本低於表格所列的最低版本,你便會受到 Node.js Brotli RCE 漏洞(CVE-2026-111497)影響,而且攻擊者已在積極利用此漏洞。

立即試用 Apidog

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 及更早版本 已終止支援(EOL):未修補,亦未評估 沒有修補程式 遷移至 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 透過 cherry-pick 套用修補程式,但沒有修改回報的版本,因此這個欄位無法用來判斷系統是否已受保護。

簡而言之(TL;DR)

問題 答案
這是甚麼? Node.js 內置 Brotli 解碼器的越界寫入漏洞,亦稱為 Node2Shell 或 HTTP2Shell
影響 程序崩潰、記憶體資料外洩或遠端程式碼執行(RCE)
嚴重程度 Node.js 評為高;NVD評為 9.8 嚴重(CVSS 3.1)
是否正遭積極利用? 是。CISA 的 KEV 目錄於 2026 年 10 月 27 日將此漏洞列入其中
是否需要驗證? 根據 NVD 的攻擊向量及Akamai 的分析,不需要
哪些用戶會受影響? 會解碼不受其控制的 Brotli 資料的應用程式:Express 5 的請求主體、fetch() 的回應,或直接呼叫 node:zlib
解決方法 更新執行環境、重新建置容器映像檔,並重新啟動程序
有沒有臨時緩解措施? 官方安全公告沒有列出任何措施。以下詳述的臨時措施可降低受影響程度,但無法涵蓋所有情況

Cronología de CVE-2026-111497: parches de Node.js el 21 de octubre, CVE publicado el 22 de octubre, tráfico de exploits detectado el 26 de octubre, inclusión en el catálogo KEV de CISA el 27 de octubre, fecha límite de KEV el 10 de noviembre, próximo lanzamiento de seguridad de Node.js el 11 de noviembre

ELLIO 在其感測器中回報了漏洞攻擊流量,距離修補程式發布僅五天,即 10 月 26 日。截獲的有效負載(payload)針對採用 x86-64 架構的 Node.js 24.22.0。雖然該有效負載的最後階段在 ELLIO 的測試中失敗,但該公司確認,標準版 24.22.0 組建可遭執行程式碼。CISA 將 11 月 10 日定為美國聯邦機構採取行動的期限,並將此漏洞在勒索軟件中的使用情況標記為「未知」。此外,Akamai 的遙測數據顯示,截至 10 月 26 日,受監察網絡中仍有 61 % 正在執行受影響版本。

Node2Shell 的運作方式:Brotli 漏洞的影響

Node2Shell 是 Node.js 執行環境內置 Brotli 解碼器中的越界寫入漏洞。解碼器處理格式錯誤的壓縮資料流時,會寫入超出內部八字節緩衝區的範圍,破壞程序記憶體。因此,漏洞可能導致伺服器崩潰、記憶體資料外洩,或在攻擊者控制下遠端執行程式碼。

根本原因在於錯誤分類不當:遇到無效的區塊變更時,解碼器把情況解讀為「需要更多輸入資料」,而非「這些資料已損毀」,因此持續將位元組寫入小型內部緩衝區。

問題出在 Google 的 Brotli 程式庫,影響版本由 1.0.3 至 1.2.0,因此並非只限於 Node.js。Node.js 團隊透過 cherry-pick 上游提交 0ed4268a,在 版本 24.22.1 及相應版本中修正了其實作。漏洞由 OpenAI Codex Security 的研究員 Khai Tran 和 Sylvie Mayer 發現並通報。

你的依賴項分析工具不會偵測到這個問題,因為解碼器屬於執行環境的一部分,而非 npm 套件。事實上,在我們的測試項目中,Express 5 執行於有漏洞的 Node.js 24.15.0 之上,npm install 顯示有 0 個漏洞。

哪些情況會面臨風險

使用有漏洞的執行環境只是其中一個因素;另一個因素是有途徑將不受信任的 Brotli 資料傳送至解碼器。我們在實驗室以 Node.js 24.22.1 測試各種情況:使用 Content-Encoding: br 標頭傳送無效但無害的本文(文字 not-valid-brotli),並向每個客戶端提供有效的 Brotli 內容。

存取途徑 測試版本 會執行解碼器? 觀察結果
Express 5 express.json() 5.3.0 (body-parser 2.4.0) 會,預設情況下 400,「解壓縮失敗」
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本身

Diagrama de vías de acceso al decodificador Brotli en node:zlib: parsers de Express 5, parsers del body de Koa y Fastify con @fastify/compress en las peticiones entrantes; fetch, axios y got en las salientes; mientras que Express 4, Fastify estándar y node:http básico no acceden a él

有兩項結果尤其值得留意。fetch() 即使請求傳送了 Accept-Encoding: identity,仍會解碼 Brotli,因為它依據回應標頭,而非請求的內容。你的應用程式呼叫的任何外部伺服器,都可能令解碼器處理其回應,使 webhook 測試服務、連結預覽產生器或 URL 匯入工具面臨風險。此外,單憑 400 回應並不能保證安全:Express 5 和不含外掛的 Fastify 都會傳回這個代碼,但只有 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,然後重新編譯
Serverless 在已部署的函式中將 process.version 記錄到日誌;不要假設平台已替你更新

然後,記得處理兩個最常見的疏忽:

  • 重新啟動所有服務。 正在執行的程序會將舊版執行檔保留在記憶體中;因此,更新磁碟上的檔案後,必須由 pm2、systemd 或你的協調器重新啟動,更新才會生效。
  • 重建所有已部署項目。 舊版映像檔仍包含有漏洞的執行環境,而以 digest 固定的映像檔則需要進行映像檔掃描,因為標籤無法顯示它們是否已套用修補程式。

最後,請在已部署的容器、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)"'

你仍在使用 Node.js 20 或 25 嗎?目前沒有任何已修正版本可供你使用。請參閲 Node.js 20 的生命週期終止(EOL)計劃,並盡快遷移。

如果今天無法更新,Node.js 的緩解措施

這些替代方案可以為你爭取時間,但都不能取代更新。

  1. 在邊緣端(edge)拒絕 br。 在反向代理伺服器或負載平衡器中封鎖 Content-Encoding: br,並確保比對時不區分大小寫,且涵蓋 gzip, br 等清單。
  2. 在應用程式中拒絕它。 將這段中介軟件放在請求本文解析器之前。在我們使用 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();
});
  1. 停用自動解壓縮。 設定 express.json({ inflate: false }) 在相同請求中回應了 415。請注意,這也會拒絕以 gzip 壓縮的本文,因此請先確認你的用戶端。
  2. 控制外發回應。 axios 支援 decompress: false,在我們的測試中可讓位元組保持未解碼狀態。相較之下,fetch() 沒有標準的停用機制,因此建議透過白名單及防火牆輸出規則,限制它可以連線的主機。
  3. 縮小影響範圍。 對 Node.js 服務進行網絡分段,並限制記憶體傾印檔(core dumps)的讀取權限;ELLIO 提醒,系統崩潰可能會令記憶體中的敏感資料透過這些檔案外洩。

請留意 ELLIO 最初發現的模式:大量突發請求使用 Brotli 編碼的本文,目的是探測哪些伺服器會解壓縮這些內容。若 JSON API 出現含有 Content-Encoding: br 的異常流量,或 worker 程序崩潰次數突然增加,便應立即調查。

確認你的 API 是否經受住更新:讓你的 Agent 進行驗證

執行環境版本變更可能會影響 TLS、DNS 和 HTTP 的行為;事實上,十月的更新在這三方面都引入了變更。不要手動核對這些差異:請交由你的開發 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

這個額外的測試案例是健康檢查,而不是漏洞利用:請求主體是純文字;在我們的測試中,易受攻擊和已修補的版本都出現相同的填充(padding)錯誤。即使如此,它仍能找出一個實際問題:我們在 Koa 的測試中遇到 500 錯誤,原因是解碼失敗未有被捕捉;而公開 API 理應回應 4xx。只可在 staging 環境執行。

run 指令參考詳細列出所有可用選項,而CI/CD 指南則示範如何在你的 pipeline 中加入相同的 JUnit 格式執行方式。Apidog 免費方案最多支援 4 位用戶。

為何 11 月 11 日是關鍵日期

Node.js 項目已預先公佈新一輪更新,適用於 26.x、24.x 和 22.x 分支,預定於 2026 年 11 月 11 日或緊接其後推出;相關漏洞再次被評為最高級別的高危漏洞。目前尚未公開相應的 CVE。請參閲我們的 11 月發佈指南,瞭解如何作好準備。

請立即套用 Brotli 修補程式,不要等到新一輪發佈才處理。漏洞詳情已公開,目前亦有活躍的漏洞利用流量;此外,你今週進行的更新也可作為下一次更新的演練:使用相同的清單、重建相同的映像檔,並執行相同的一組測試。PHP2Shell 和 React2Shell 也出現過完全相同的模式。

常見問題(FAQ)

CVE-2026-111497 正遭受活躍攻擊嗎? 是。CISA 於 2026 年 10 月 27 日以 Google Brotli 條目將其加入已知遭利用漏洞目錄(KEV),而 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 項目不會評估已達支援週期終止(EOL)且不再接收修補程式的版本。請視 20.x 和 25.x 為尚未修補、亦未經評估的版本,並遷移至仍受支援的版本。

除了 Node.js,其他技術也會受影響嗎? 會。GitHub 安全公告列出 PyPI 套件 brotli 和 brotlicffi;多家供應商亦已公佈 Bun 1.4.4 和 .NET 的修補程式。請分別更新每個解碼器,因為更新 Node.js 只會保護其內置副本。

來源:DEV Community · dev.to