Brotliの脆弱性(CVE-2026-111497)は、Node.jsの外へ広がった。手元のMacとWordPressのサーバーで、何を確かめればいいのか

Brotliの脆弱性、Node.jsの外へ。CVE-2026-111497の影響範囲と確認。中心の圧縮データから、いくつもの実行環境へ線が伸びる図 Web Development
この記事は約11分で読めます。

Node.jsを上げたら、Brotliの件は終わりだったのでしょうか。

先に答えを書いておきます。
手元のMacについては、終わっていました。
ただ、そう言い切るまでに、確かめることがいくつも増えました。

10月22日、手元のMacのNode.jsを25.8.1から26.12.1に上げました。その記録は「Node.js脆弱性(CVE-2026-111497):手元のMacのNode.jsは、修正版が出ない25.xだった」に書いています。
あの時点では、Node.jsの脆弱性の1つとして読んでいました。
そのあとの1週間で、話はNode.jsの外へ広がっていきました。

10月21日〜23日:Brotliは、Node.jsの外にもいた

CVE-2026-111497は、GoogleのBrotliのC言語実装にある不具合です。
細工した圧縮データを展開させると、決められた範囲の外へ書き込みが起きます。プロセスが落ちる、メモリの中身が漏れる、最悪の場合はコードを実行される。そういう種類の脆弱性です。
Node.jsが公表したので、最初は「Node2Shell」と呼ばれました。HTTPの通信で広く使われていることから「HTTP2Shell」、ほかに「Broccoli2Shell」という呼び名もあります。HTTP/2だけの話ではありません。

Node.jsは、Brotliを中に抱えている実行環境の1つにすぎませんでした。
22日から23日にかけて、PythonのBrotliとbrotlicffiのパッケージが直り、BunとEnvoy、Istioにも同じ問題があると分かりました。
調べてみると、Brotliの上流では2月27日の時点でもう修正が入っていました。セキュリティの修正としては告知されていなかったので、Brotliを取り込んでいるほかのソフトは、古い版のまま半年以上過ごしていたことになります。

10月25日〜27日:.NET、Windows版PHP、そしてCISA

25日には、Microsoftが.NETの緊急更新を出しました。26日にはJPCERT/CCが注意喚起を出し、DebianとAlpineが修正しています。
PHPは、Windows版のビルドだけが作り直されました。PHPのソースのリリースは変わっていません。Windows版のPHPはBrotliを同梱していて、curlでレスポンスを自動で展開する設定にしている場合に通り道になる、という説明です。自動展開は既定では無効とされています。
27日には、米国のCISAが、実際に悪用が確認された脆弱性の一覧(KEV)にこの件を加えました。米連邦機関の対応期限は11月10日です。

前回の記事では、公開された攻撃コードは通常のビルドではコード実行に至らず、クラッシュとメモリの一部の読み取りにとどまった、と書きました。
そこは、その後で状況が変わっています。
Impervaは、Node.js 24.22.0(Linuxのarm64)で、何度か試したうえでコード実行に成功したと報告しています。攻撃コードは公開していません。ELLIOは10月26日、Node.js 24.22.0(x86-64)を狙った攻撃の試みを観測したと報告しました。こちらはTenableが独自には確認していません。
一方で、攻撃はNode.jsのビルドごとに合わせ込む必要があり、ELLIOの実験でもほとんどはワーカープロセスが落ちるだけで、22.23.3や26.12.0では1万回試してもシェルは取れなかったそうです。
簡単に狙えるものではありません。それでも、狙われ始めてはいます。今はそう読んでいます。

影響するもの、しないもの

ここまでの流れと、どこが対象になるのかを、図にしておきます。

2月の上流修正から、10月21日のNode.js公表、Python・Bun・Envoy・.NETへの広がり、10月27日のCISA KEV追加までの時系列の図

Brotliで圧縮して送る側は対象外で、受け取ったデータを展開する側だけが対象になることを示す図

不具合があるのは、展開する側(デコーダー)だけです。
Webサーバーがレスポンスを圧縮して送るだけなら、関係ありません。ApacheのBrotli圧縮(mod_brotli)は圧縮だけで、展開はしないので対象外とされています。
対象になるのは、外から受け取ったBrotliのデータを展開するときです。圧縮されたリクエストを受け付けるサーバーと、外のサーバーから圧縮されたレスポンスを受け取るクライアント。この2つが通り道になります。
影響するBrotliの版は1.0.3〜1.0.9、1.1.0、1.2.0で、修正版は1.0.10、1.1.1、1.2.1です。CVSSは、Googleの評価で9.2(CVSS v4.0)、.NETについてのMicrosoftの評価で8.1(CVSS v3.1)です。
報じられている主なものを、表にまとめました。

対象 修正版 補足
Brotli(上流) 1.0.10/1.1.1/1.2.1 OSのlibbrotliを上げても、Brotliを抱えているアプリは別に更新が要る
Node.js 22.23.4/24.22.1/26.12.1 20・23・25系はサポート切れで修正なし
Bun 1.4.4 コンパイル済みの実行ファイルは作り直しが要る
Python Brotli/brotlicffi 1.2.1/1.2.1.0 入っていると、requests、urllib3、httpx、aiohttpが自動で展開する
.NET 8.0.33/9.0.22/10.0.14/11 RC3 Brotliの展開を自分で有効にしたアプリだけが対象。.NET 7は修正なし、.NET Frameworkは影響なし
Windows版PHP 8.2.35-1/8.3.36-1/8.4.27-1/8.5.12-1 curlの自動展開を有効にしている場合。PHPのソース版は変更なし
PHPのbrotli拡張 0.21.1 Brotli 1.2.1を同梱
Rubyのbrotli gem 0.9.1 修正前のlibbrotliに対してはビルドを拒む
Java brotli4j(Netty) 1.24.0
Go(andybalholm/brotli) v1.2.7
Envoy 1.37.8/1.38.6/1.39.3/1.40.0 Brotliの展開フィルターを設定しているときだけ
Istio 1.29.9/1.30.6/1.31.2 既定ではBrotliを展開しない
Git for Windows 2.56.0.windows.4 同梱のcurlがBrotliで展開する

ほかに、FFmpeg(libjxl経由)、Apache Arrow、ClickHouseでも報告があります。
Linuxのディストリビューションでは、Debian、Alpine、Ubuntu、Amazon Linux 2023が修正済みです。RHELの通常のリポジトリ、SUSE、Fedora 43〜45は、29日時点で修正版が出ていません。
ブラウザーは、ChromeとFirefoxが第三者のまとめた一覧で「追跡が始まる前に修正済み」とされています。ただ、GoogleやMozillaの公式な説明は見つけられませんでした。Safariについては、情報が見当たりません。

10月29日 昼:手元のMacで打った6行

手元のMacで、Brotliを展開しそうなものを順に見ました。前回と同じM5のMac(macOS 27)です。打ったのは次の6行で、出力はそのまま載せています。

読んだ結果を、表にしました。

見たもの 出力 読み方
Node.js v26.12.1 -17 修正版。-17が出るのは修正の入ったBrotliの印
Homebrewのbrotli stable 1.2.1 Homebrewが今配っている版は修正版。手元も前回のbrew upgradeで1.2.0から1.2.1に上がっている
Homebrewのcurl 8.23.0 [keg-only] keg-onlyなので、入っていてもふつうの curl コマンドでは呼ばれない
いつもの curl 8.7.1、Featuresにbrotliなし macOSに最初から入っているcurl。Brotliで展開しないので、通り道にならない
Python 何も出ない BrotliもbrotlicffiもPythonに入っていない

Node.jsの -17 は、修正で足された定数です。Brotliの版の表示は修正の前後で変わらないことがあるそうなので、版の文字列よりこちらを見るほうが確実だと思います。
気になったのはcurlでした。
Homebrewのcurlは、修正版のbrotli 1.2.1に依存しています。ただ、keg-onlyなので、入れていたとしてもPATHには出てきません。ターミナルで curl と打ったときに動くのは、macOSに最初から入っている /usr/bin/curl です。こちらは8.7.1で、Featuresの行にbrotliがありません。なお、表示の「x86_64-apple-darwin26.0」は、macOSに付属するcurlの表示で、Apple Siliconの機械でもこう出ます。
Brotliに対応していないので、–compressed を付けてもBrotliでは受け取らない、ということです。
古いcurlなのに、今回に限っては、それで助かっている。少し皮肉な結果でした。
Windowsでは逆に、Git for Windowsに同梱されたcurlがBrotli 1.2.0を抱えていて、展開までしていた、という検証が出ています。同じ「curl」でも、どこから来たcurlかで話が変わります。

WordPressのサーバーでは

WordPressは、PHPで動いています。
PHP本体は、Linux向けのソースのリリースに変更がありません。今回作り直されたのは、Brotliを同梱しているWindows版のビルドだけです。
Linuxのサーバーでは、PHPのcurlが使うlibbrotliは、OS側の部品です。それを更新するのは、レンタルサーバーならホスティング会社の仕事になります。自分でできるのは、告知を待つことと、そもそもcurlがBrotliに対応しているかを見ておくことくらいです。phpinfo()のcurlの欄に、Brotliへの対応の有無が出ている場合があります。
このサイトを置いているXserverは、Brotliで圧縮して配信しています。これは圧縮する側の仕事で、ブラウザーへ送るデータを縮めているだけです。展開はしていないので、今回の不具合の通り道にはなりません。

すぐに上げられないとき

修正版に上げられない事情がある場合の、つなぎの対策も報じられています。どれも、修正版に上げるまでの間に合わせです。

場面 対策
受け取るリクエスト Content-Encodingに br を含むリクエストを、展開する前にプロキシやミドルウェアで拒否する
受け取るレスポンス Accept-Encodingから br を外すだけでは足りない。br で返ってきたレスポンス自体を、展開する前に止める
curl スクリプトや .curlrc から –compressed を外す。libcurlでは CURLOPT_ACCEPT_ENCODING を設定しない
Python Brotliとbrotlicffi、httpx[brotli] などの追加指定を外す
上げたあと プロセスを再起動する。コンテナはイメージを作り直す。動いているものが修正版を読み込んでいるか確かめる

Accept-Encodingの件は、意外でした。Pythonのrequestsは、Brotliが入っていると、こちらから「Brotliは要らない」と送っても、br で返ってきたものは展開してしまう、という検証結果が出ています。送る側の宣言ではなく、受け取った側の動きで決まる、ということです。

10月29日の時点で、CISAが米連邦機関に求めている対応期限は11月10日です。RHELの通常のリポジトリとSUSEには、まだ修正版が出ていません。

参考にした情報

Rapls Works のその他の記事

Web Development
この記事を書いた人
rapls

WordPress のプラグインを作っているフリーランスエンジニア、Rapls です。Web 開発は6年以上。WordPress.org でプラグインを7本公開・保守しながら、日本語ロケールの翻訳エディター(PTE)も務めています。このブログには、現場で実際にハマって、調べて、直した話を書いています。

raplsをフォローする
raplsをフォローする

コメント

タイトルとURLをコピーしました