返回
2026/10/26
HTTP2Shell(CVE-2026-111497):更新二進位檔並不會修補正在執行的程序
HTTP2Shell 背後的 Brotli 漏洞波及 Node.js、Bun 與 Python。本文說明如何確認執行中程序的實際曝險,並安全重新啟動 AI 代理。
2026 年 10 月 21 日,Node.js 釋出了 CVE-2026-111497 的修正。此漏洞是 Google Brotli 解碼器中的越界寫入。其後數日內,Bun、Python 的 brotli 與 brotlicffi 套件、Envoy 及 Istio 相繼發布安全公告,資安媒體先將其稱為 Node2Shell,後來又稱為 HTTP2Shell。儘管名稱如此,它並不是 HTTP/2 協定的缺陷,而是一個解壓縮漏洞:凡是軟體會解碼攻擊者可影響之 Brotli 資料的地方,都需要留意。
本文整理哪些已經證實、哪些僅是可能,以及如何檢查自己的系統。同時分享我們自身應變過程中的一個教訓:安裝已修正的二進位檔,並不能修正仍在執行舊版本的程序。在我們的環境中,已安裝的 Claude Code 更新之後,長時間執行的 Claude Code 工作階段仍沿用舊的內嵌執行環境。
重點摘要
- 受影響版本:上游 Brotli 1.0.3 至 1.2.0。已修正版本:1.0.10、1.1.1 及 1.2.1。內含 Brotli 的產品需要各自釋出修正版本。
- 曝險需要一條實際路徑:攻擊者可影響的 Brotli 資料到達有漏洞的解碼器。單憑產品名稱或網路可達,並不能證明有曝險。
- 要檢查執行中的程序,而不只是已安裝的套件。程序在重新啟動之前,會一直使用其啟動時的執行環境。
- 有狀態的 AI 代理要逐一重新啟動,並先交接其事件、核准與工作狀態。
1. 漏洞是什麼
解碼器在遇到無效的區塊切換時,回報的是「需要更多輸入」,而非永久性的格式錯誤。於是串流呼叫端會持續送入位元組,解碼器將它們附加到一個 8 位元組的內部緩衝區,寫出了緩衝區尾端。Node.js 公告指出,能夠提供由應用程式透過 node:zlib 解壓縮之 Brotli 資料的攻擊者,「可以破壞程序記憶體,進而可能導致當機、程序記憶體外洩或遠端程式碼執行」。
各方的嚴重性評等不一。Node.js 評為 High。GitHub 針對 Python 套件的公告與 Envoy 公告評為 Critical,CVSS 4.0 分數 9.2。Ubuntu 目前將其列為 Medium 優先等級。截至 10 月 26 日,CVE 紀錄中 CISA 的評估將遭利用情況列為「none」,此 CVE 也未列入 CISA 的已知遭利用漏洞(KEV)目錄。但 Node.js 公告仍將遠端程式碼執行列為可能後果,因此不要把「尚無攻擊通報」當作可以觀望的理由。
2. 前提條件:什麼情況下才真正曝險
以下三個條件必須同時成立:
- 程序中載入了有漏洞的解碼器:內含的或系統的 Brotli 函式庫位於受影響版本範圍內,且未經修正或未向下移植修補。
- 有程式碼呼叫它:明確的解壓縮,或自動解碼
Content-Encoding: br。 - 輸入可受攻擊者影響:來自任意 URL 的回應、上傳的檔案、傳入的請求主體,或惡意網路上的明文 HTTP 流量。
自動解碼是團隊最常忽略的路徑。Bun 公告指出,fetch 預設會送出 Accept-Encoding: br 並解碼回應,因此任何擷取不受信任 URL 的 Bun 程式都存在這條路徑。在 Python 中,一旦安裝了 brotli 或 brotlicffi,urllib3 就會自動解碼 Content-Encoding: br 回應,requests 也會在請求中宣告支援 br。即使你自己的程式碼從未提到 Brotli,也是如此。Envoy 與 Istio 只有在設定了 Brotli 解壓縮器時才會曝險。
3. 已確認受影響與僅可能受影響
狀態截至 2026 年 10 月 26 日。情況變化很快,請查閱連結中的公告。
| 元件 | 狀態 | 修正版本 |
|---|---|---|
| 上游 Brotli(C) | 已確認:1.0.3 至 1.2.0 | 1.0.10、1.1.1、1.2.1 |
| Node.js 22、24、26 | 已確認 | 22.23.4、24.22.1、26.12.1 |
| Node.js 20 及更舊版本(已終止支援) | 未評估;Node.js 將終止支援的版本線一律視為受影響 | 改用受支援的版本線 |
| Bun(包含編譯後的執行檔) | 已確認:1.0.21 至 1.4.3 | 1.4.4,並重新建置編譯後的應用程式 |
| Python brotli / brotlicffi | 已確認:自 1.0.3 起 | 1.2.1 / 1.2.1.0 |
| Envoy(已設定 Brotli 解壓縮器) | 已確認 | 1.40.0、1.39.3、1.38.6、1.37.8(不受支援的 1.36 分支為 1.36.12) |
| Istio(已啟用 Brotli 解壓縮) | 已確認 | 1.31.2、1.30.6、1.29.9(1.29 的最終版本) |
| Ubuntu brotli 套件 | 待評估(所有版本) | 尚無修正套件 |
| Ubuntu nodejs 套件 | 20.04 上有漏洞(內含 Brotli)。22.04 及更新版本使用系統 Brotli,因此情況與上一列相同 | 參見 Ubuntu 追蹤頁面 |
| Debian brotli 套件 | bookworm 與 trixie 已修正;forky 尚未修正 | 1.0.9-2+deb12u1、1.1.0-2+deb13u1 |
| Chrome、Electron 及 Electron 應用程式 | 未知:未找到廠商聲明 | 關注廠商版本說明 |
關於最後一列:Chrome 與 Electron 各自內含自己的 Brotli 副本,而 Electron 應用程式還內嵌了 Node.js 執行環境。截至撰文時,最新的 Electron 穩定版(45.0.0、44.9.3 及 43.8.3,皆於 10 月 21 日發布)所列 Node.js 版本為 24.22.0,而非 24.22.1,其版本說明也未提及此 CVE。10 月 23 日的 Electron 預先發行版已包含 Node.js 24.22.1,因此穩定版修正很可能即將推出,但目前尚未釋出。這表示以 Electron 打造的桌面應用程式可能曝險,而非已確認有漏洞。聊天用戶端與 AI 桌面工具亦同:在判定其受影響或安全之前,請先查閱各廠商自己的聲明。
還有一個陷阱:回報的函式庫版本號無論如何都不能當作證據。已修正的 Node.js 22.23.4 回報的 process.versions.brotli 仍是 1.1.0,因為修正是以向下移植方式加入的。各發行版也是如此。應依據產品的修正版本或發行版的安全狀態判斷,而非 Brotli 的版本字串。
4. 我們在自身環境中的發現
在進行任何變更之前,我們先做了唯讀盤點。以下是經過匿名化處理的觀察結果,已確認的發現與無法驗證的風險分開列出。
已確認的觀察
- 已安裝的 Claude Code 早已更新,但有十幾個長時間執行的工作階段仍在執行數週前啟動的舊版本,從未重新啟動過。
- 我們第一次清點時漏掉了其中三個。它們在另一個輔助程序之下執行,所以依命令列搜尋時沒有比對到。改依執行檔搜尋才找到它們。
- 舊版本的檔案已被更新程式從磁碟上刪除,因此無法讀取這些程序內嵌的 Bun 版本。
- 一個透過套件管理工具安裝、遺留下來的舊版 Claude Code 內嵌了 Bun 1.4.0。正常運作中沒有任何東西使用它,但某條備援路徑可能會用到。在證明沒有任何相依之後,我們將其移除。
- 一台伺服器上仍安裝著一個未使用、已終止支援的 Node.js 執行環境。我們以同樣方式將其移除。
- 我們升級後的目前 Claude Code 版本(2.1.310)包含 Bun 1.4.4。我們透過檢查二進位檔確認了這一點。Anthropic 的變更紀錄並未提及此 CVE,因此請以同樣方法檢查你自己的版本。
未經驗證,視為風險處理
- 舊工作階段是否確實有漏洞。它們的 Bun 版本無法讀取。已修正的 Bun 1.4.4 約在 10 月 22 日才推出,晚於這些版本,因此我們將其視為受影響。
- 攻擊者能否透過這些工作階段觸及解碼器,例如讓其擷取惡意 URL。依據 Bun 文件所述的
fetch行為,這條路徑合理可能,但我們並未證實。 - 其他內含自己 Brotli 副本的軟體是否受影響。在沒有廠商聲明的情況下,我們對照廠商的版本發布追蹤該產品,而不是假定其安全或有漏洞。
我們沒有發現任何遭利用的證據。但我們也沒有把這當作安全的證明:修正之道是消除曝險,而不是靠論證把它說掉。
5. 偵測與修補檢查清單
找出相依套件
不只要在以套件形式安裝的地方尋找 Brotli,也要在它被內含的地方尋找。檢查 SBOM 與容器映像檔中的 Node.js、Bun、Python 套件、Envoy 以及靜態連結的 Brotli。檢查 Python 的間接相依套件,因為 Brotli 經常以選用附加元件的形式被帶入。
# Node.js: compare with 22.23.4 / 24.22.1 / 26.12.1
node -p process.version
# Python packages: run once per interpreter and virtual environment
python -m pip list 2>/dev/null | grep -iE '^(brotli|brotlicffi) '
pipdeptree -r -p brotli # what pulled it in
# Debian / Ubuntu system library (then check the distro tracker)
dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\n' 'libbrotli*'
# Container images, with an SBOM scanner such as Syft
syft <image> | grep -iE 'brotli|node|bun'
找出內嵌的執行環境
以 bun build --compile 建置的程式會自帶一份 Bun。Bun 公告指出,在以 1.4.4 重新建置之前,它們一直受影響。在建置機上升級 Bun,並不會改變已經部署的二進位檔。
# The Bun version inside a compiled executable
grep -aoE 'Bun v1\.[0-9]+\.[0-9]+' /path/to/binary | sort -u
找出執行中的程序
檢查正在執行的東西,而不是已安裝的東西。在 Linux 上,執行檔已被取代或刪除的程序會顯示 (deleted)。這強烈顯示它仍在執行舊版本。
# Processes still running a deleted (replaced) executable (run as root to see all users)
for p in /proc/[0-9]*; do
e=$(readlink "$p/exe" 2>/dev/null) || continue
case "$e" in *"(deleted)") echo "${p#/proc/} $e";; esac
done
# Processes older than the fix
pgrep -af 'node|bun|claude' # then: ps -o pid,lstart,args -p <pid>
在 macOS 上,lsof -p <pid> 會顯示程序載入的執行檔。請依執行檔比對,而不是依程序名稱,否則會漏掉輔助程序與背景工作程序。
修正、重新建置、重新部署
- 升級至表中的修正版本。有向下移植修補的地方,使用發行版提供的已修補套件。
- 重新建置容器映像檔與編譯後的執行檔,然後重新部署。已修補的基礎映像檔,對你尚未重新建置的映像檔毫無作用。
- 在證明沒有任何服務、作業或指令碼相依之後,移除未使用的執行環境與遺留安裝。保留復原手段。
- 在尚無修正的情況下,於安全可行之處停用對不受信任輸入的 Brotli 解碼。以 Bun 而言,可針對個別請求使用
fetch(url, { decompress: false })。為每項緩解措施指定負責人與截止日期。
重新啟動並驗證
重新啟動後,檢查新程序實際使用的執行檔與執行環境版本。接著檢查業務產出:佇列已清空、排程作業執行成功、監控警示正常送達。升級指令執行成功,只能證明該指令有執行過。
6. 安全地重新啟動常駐 AI 代理
長時間執行的 AI 代理持有狀態:待處理的工具呼叫、核准、排入佇列的訊息以及對工作的認領。一次全部重新啟動可能會遺失這些狀態。以下順序在我們這裡行之有效:
- 盤點每個工作階段:執行檔版本、狀態(閒置、等待或忙碌)、最後活動時間、待處理工作、正在等待或持有的核准、未確認的事件,以及其復原方式。
- 把核准移出記憶體。只存在於工作階段對話中的核准,重新啟動後就會遺失。重新啟動前,將每項待處理核准(核准了什麼、由誰核准、針對哪項確切變更)記錄在持久的位置,例如工單或 pull request 中。重新啟動後,確認工作階段仍看得到它。如有疑慮,寧可重新請求核准,也不要自行假定。
- 先證明替代方案可行。確認在已修正版本上執行的工作階段已能正常運作,且有一個獨立於舊工作階段的事件監看程式在執行,讓任何事件都不依賴某個待重新啟動的工作階段。
- 先重新啟動閒置的工作階段,一次一個。每重新啟動一個,都要驗證舊程序已結束、新程序執行的是已修正的執行檔、對話紀錄完整,且所有遠端連線皆已恢復。然後再處理下一個。
- 最忙碌的負責者放在最後,於任務之間重新啟動。讓它撰寫一份交接說明,僅在待處理事項與未確認事件皆為零時停止其監看程式,然後重新啟動,再確認其監看程式已從儲存的位置繼續,沒有遺漏任何內容。
- 預期重新連線時會收到排隊中的輸入。我們有一個重新啟動後的工作階段收到一則已等待十天的訊息,並據此採取了行動。重新啟動前請檢查每個工作階段的收件匣,並告知其負責人。
- 停止並呈報:若任何步驟無法證明工作已復原,就停下來呈報。不要退回到全部強制終止的做法。
開始之前先定義「完成」。完成代表:沒有任何執行中的程序使用受影響的版本,每個例外都有記錄,並有負責人與複查日期,且業務檢查全數通過。「套件已升級」並不等於完成。
Global
Japan
Korea
China
Vietnam
Thailand
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia