Brotli デコーダの真偽値ひとつが、Node.js から Python、HTTP サーバーまで同じ対応期限に追い込んだ
DecodeBlockTypeAndLength() が返す真偽値は「壊れたデータ」と「入力が足りない」を区別できない。細工したストリームはバッファの境界の外に書き込む。修正は2月に上流へ入っていたが、脆弱性として扱われないまま、今月になって各ランタイムが一斉に更新した。
日本語
コピー

TL;DR
Brotli は Google 製の広く使われている圧縮ライブラリだ。10 月 21 日(水)、NodeJS は CVE-2026-111497 を公表した。通称「node2shell」。攻撃者が制御する Brotli データを展開する Node.js プロセスで、メモリ漏洩や任意コード実行が引き起こされる可能性がある。10 月 22 日(木)には Python も、Python パッケージが同じ CVE-2026-111497 の影響を受けると公表した。
10 月 23 日(金)、この CVE が HTTP を使う他の主要言語やサービスアプリケーションにも影響し、パッチがまだ完全には出揃っていないことが明らかになった。
自分のライブラリが依存として Brotli をデコードしていないか確認してほしい。広範な告知に注意を払い、可能になり次第すぐアップグレードできるよう備えておくこと。影響を受ける可能性のあるライブラリやアプリケーションにパッチがない場合は、パッチが出るまで Brotli のデコードを無効化することを勧める。
太平洋時間 16:12 更新。libbrotli、Python、C++、NodeJS、bun、Envoy のパッチが利用可能で、他も続く見込み。Apache と Nginx はデフォルトでは brotli をデコードしない。
太平洋時間 16:15 更新。OpenAI はこの脆弱性を 2 月に発見していたと明かした。根本原因は当時 Brotli のソースコードで修正済みだったが、それがセキュリティ脆弱性につながるとは認識されていなかった。OpenAI のアドバイザリはこちら。
Brotli とは
Brotli は Google が開発した可逆圧縮アルゴリズム兼データフォーマットだ。データを小さくして保存したりインターネット経由で送ったりするための手段で、ソフトウェアが展開して元のデータに戻す。HTML、CSS、JavaScript といった Web コンテンツを圧縮する HTTP 圧縮で広く使われている。
CVE-2026-111497 とは
CVE-2026-111497 は Google Brotli デコーダの境界外書き込みで、全プラットフォームのバージョン 1.0.3 から 1.2.0 が該当する。数日前に発表された Node2Shell の背後にあるのも同じ Brotli デコーダの欠陥だ。リモートの未認証の攻撃者が細工した Brotli 圧縮ストリームを送りつけることで、メモリを破壊し、機密データを漏洩させ、プロセスをクラッシュさせ、あるいは任意コードを実行させる可能性がある。CVSS v4.0 スコアは 9.2(Critical)で、Node.js は同梱の Brotli ライブラリを通じて影響を受ける。
Brotli デコーダにはバグがあり、本来なら拒否すべきデータを受け入れ続けてしまう。余分なバイトが小さな作業バッファをあふれさせ、プログラムのメモリを破壊するおそれがある。攻撃者はこの破壊を利用して、自分たちのコードなど任意のコードを実行させられる。
OpenAI が 2 月に発見し、双方向で成立する未認証のリモートコード実行として報告した。悪意あるクライアントは未修正のサーバーを、悪意あるサーバーは圧縮レスポンスを受け入れる未修正のクライアントを乗っ取れる。
根本原因は 2 月に Brotli のソースコード上で修正されていたが、当時はセキュリティ問題として認識されず、修正を含むリリースは今回まで出ていなかった。つまり Brotli を同梱するプロジェクトはすべて、自前でアップデートを配布する必要がある。
Brotli 1.2.0 以前、または brotlicffi 1.2.0.x が入っている環境は影響を受ける。requests、httpx、aiohttp といった HTTP クライアントは、これらのパッケージがあれば自動で読み込むためだ。Brotli 1.2.1 または brotlicffi 1.2.1.0 にアップグレードし、これらを同梱するコンテナイメージはすべて再ビルドしてほしい。10 月 23 日時点で、アドバイザリデータベースはこの CVE をどちらの PyPI パッケージにも紐づけていない。そのため pip-audit、Dependabot、Safety は脆弱なバージョンをまだ検出しない。
Aikido Intel で追跡している内容はこちらで確認できる。
影響を受けないソフトウェアについて言えば、Apache の標準的な mod_brotli は Brotli をデコードしない。
HTTP2Shell CVE-2026-111497 のパッチ適用方法
CVE-2026-111497 については、影響を受けるランタイムまたは Brotli ライブラリを更新する。
- Node.js: 22.23.4、24.22.1、26.12.1、またはそれぞれのリリースラインで新しいサポート対象リリースにアップグレードする。
- ネイティブ Brotli / libbrotli: 1.2.1 以降にアップグレードする。古いリリースラインでは、修正済みの 1.0.10 または 1.1.1 を使う。
- Python パッケージ: インストールされている箇所すべてで、Brotli を 1.2.1 以降、brotlicffi を 1.2.1.0 以降にアップグレードする。
- curl / libcurl: Brotli 依存を 1.2.1、修正済みの古いリリース、またはベンダーのセキュリティ修正パッケージに更新する。同梱版や静的リンク版は、アプリケーションの再ビルドが必要になる。
- Bun: 1.4.4 以降にアップグレードする。Bun を同梱したコンパイル済み実行ファイルは再ビルドする。
- Envoy: 1.40.0、1.39.3、1.38.6、1.37.8、またはサポート対象ブランチの新しいリリースにアップグレードする。1.36.12 にも修正は含まれるが、1.36 ブランチはサポート対象外だ。
- Istio: 修正は 1.29.9、1.30.6、1.31.2 に含まれる。それぞれのラインで新しいサポート対象リリースを使う。1.29 ブランチはサポート終了となっている。
- OS パッケージ: ベンダーのセキュリティアップデートをインストールする。ベンダーはアップストリームのバージョン番号を変えずに修正をバックポートする場合がある。
- その他の HTTP サーバー、リバースプロキシ、API ゲートウェイ、HTTP クライアント: 使用しているランタイムまたは Brotli ライブラリを更新する。Brotli が製品に同梱されている場合は、この CVE に明示的に対応した製品ベンダーのリリースをインストールする。マネージドサービスでは、プロバイダーに修正状況を確認する。
依存関係のロックを更新し、影響を受けるアプリケーションとコンテナイメージを再ビルドして再デプロイし、サービスを再起動する。稼働中のワークロードが修正済みコンポーネントを使っていることを確認すること。
| プロジェクト | パッチの状況 | 修正バージョン | 備考 |
|---|---|---|---|
| Node.js | パッチあり | 22.23.4 · 24.22.1 · 26.12.1 | サポート対象のリリースラインを使う。 |
| Bun | パッチあり | 1.4.4 | Brotli 1.2.1 を含む。 |
| Envoy | パッチあり | 1.40.0 · 1.39.3 · 1.38.6 · 1.37.8 | 1.36.12 にも修正は含まれるが、1.36 はサポート対象外。サポートされているブランチを使う。 |
| Istio | パッチあり | 1.29.9 · 1.30.6 · 1.31.2 | 1.29 は EOL のため、サポート対象のラインへ移行する。 |
| Google Brotli(upstream) | パッチあり | 1.0.10 · 1.1.1 · 1.2.1 | 使用しているライブラリのブランチに合わせて修正版を選ぶ。 |
すぐにアップグレードできない場合の対処
アップグレードの準備を進める間、以下の回避策で露出を減らせる。
- Python アプリケーション: Brotli サポートが任意である場合、影響を受ける環境から Brotli と brotlicffi の両方をアンインストールする。
httpx[brotli]などの依存関係の extras や、これらを再インストールする他の要件を削除し、依存関係のロックを再生成してワークロードを再ビルド・再起動する。HTTPX、Requests、urllib3 はこれらの任意パッケージがなくても gzip と deflate をサポートする。ただし、それでも Brotli を送ってくるサーバーでは、応答が読めなくなるかアプリケーションエラーになる可能性がある。自動フォールバックは保証されない。- Python パッケージを両方アンインストールしてワークロードを再起動すると、これらのパッケージが受信・送信データに対して提供していたデコード経路はなくなる。他のランタイム、ライブラリ、製品に同梱された別個の Brotli デコーダは削除されない。
- 受信 HTTP リクエスト:
Content-Encodingにbrが含まれるリクエストを、脆弱なデコーダがボディを処理する前に、リバースプロキシ、ロードバランサー、またはアプリケーションミドルウェアで拒否する。brは、エンコーディングのリスト内も含め、大文字小文字を区別せずにマッチさせる。 - 送信 HTTP リクエスト:
Accept-Encodingからbrを削除する。あわせて Brotli のレスポンスデコードを無効にするか、デコードを始める前にContent-Encodingにbrが含まれるレスポンスを拒否する。このチェックは自動のボディ処理より前に行う。クライアントがレスポンスをダウンロードしてデコードした後にチェックしても手遅れになる。
Accept-Encoding を変えるだけでは足りない。クライアントが何を通知していても、悪意あるサーバーは Brotli のレスポンスを送りつけることができ、urllib3 はレスポンスの Content-Encoding ヘッダーを見てデコーダを選ぶ。
影響を受けるコンポーネントにパッチが当たり、動作確認が済むまでは、これらの制御を維持すること。ベンダーが新たな影響コンポーネントや攻撃経路を確認したら、カバレッジを見直す。
Aikido が CVE-2026-111497 にどう役立つか
Aikido は、リポジトリやコンテナイメージ、依存関係の中にある脆弱なバージョンの Brotli と brotlicffi を検出する。推移的依存として入り込んでいる場合も対象になる。ダッシュボードを見れば、どのサービスがまだ脆弱なバージョンで動いているかが分かるので、外部サーバーを呼び出すものや圧縮されたリクエストボディを受け取るものから先にアップグレードできる。
アップグレード後は、Aikido で検出結果が消えたかを確認する。
経緯
Brotli は Google 製の広く使われている圧縮ライブラリだ。10 月 21 日(水)、Node.js は CVE-2026-111497 を公開した。通称「node2shell」。攻撃者が制御する Brotli データを展開する Node.js プロセスで、メモリの漏えいや任意コード実行が起きる。アプリやライブラリが不正な Brotli データを展開している場合(組み込みの fetch() や body-parser など)に影響を受けた。
翌日、Python は同じ欠陥を修正するセキュリティアップデートを公開した。Python のパッケージも CVE-2026-111497 の影響を受けていた。このライブラリは下流で広く組み込まれているため、Brotli の欠陥はさらに多くの言語やサービスアプリケーションに及ぶ可能性がある。実は OpenAI は 2 月にこの問題を発見していた。
CVE-2026-111497 の技術的詳細
欠陥は DecodeBlockTypeAndLength() にある。この関数はブロックの切り替え、つまり Brotli ストリームが使うハフマン木を変える箇所を処理する。脆弱なバージョンではこの関数が単なる真偽値を返し、BROTLI_FALSE は「このストリームは不正だ」とも「入力がもっと必要だ」とも取れる。呼び出し側はこの 2 つを区別できず、高速パスではデコーダが戻り値をそのまま捨ててしまう。
細工されたストリームは、ブロックタイプを 1 つだけ宣言してからそのブロックの長さを使い切ることができる。これにより、成功し得ない切り替えが強制される。するとデコーダは、完了しているストリームに対して入力がもっと必要だと報告するか、すでに持っているブロック状態のままデコードを続けるかのどちらかになる。後者の経路が範囲外書き込みにつながる。
上流の修正 google/brotli commit 0ed4268 では、この関数がエラーコードを返すようになり、新しいエラー BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17) が追加された。デコードはセーフパスとファストパスの両方で、フォーマットエラーが発生した時点で停止する。OSM は Brotli 1.2.0 と 1.2.1 のソース配布物を diff し、1.2.1 の差分がバージョン番号の更新と、このコミットによるデコーダの変更だけであることを確認した。
Python ライブラリにおける Brotli の脆弱性 (CVE-2026-111497)
Node2Shell の背後にある Brotli の欠陥 (CVE-2026-111497) は Python にも影響する。PyPI の Brotli と brotlicffi という 2 つのパッケージは、Node.js が同梱しているのと同じ脆弱な Brotli デコーダをコンパイルしている。公式のアドバイザリが GitHub に投稿された。Brotli のダウンロード数は月間 8,280 万回。
実行している Python 環境のいずれかに Brotli 1.2.0 以前、または brotlicffi 1.2.0.x がインストールされていれば影響を受ける。requests や httpx といったよく使われる HTTP クライアントは、これらのパッケージが存在すれば自動的に読み込む。Scrapy のように Brotli を依存関係として自動でインストールするパッケージもあれば、明示的に指定しないと入らないものもある。攻撃者は、アプリが送信したリクエストに対して悪意ある Brotli レスポンスを返すか、Brotli で圧縮したリクエストボディをアプリに送ることで、脆弱なデコーダに到達できる。つまり、自分のコードのどこにも Brotli を import していなくても、アプリが露出する可能性がある。よく使われる推移的依存関係なので、自分のシステムを確認してほしい。
修正するには、パッチ済みのリリースにアップグレードする。
- Brotli → 1.2.1
- brotlicffi → 1.2.1.0
修正版のリリースノートはいずれもこの CVE に触れていない。10 月 23 日時点で、アドバイザリデータベースはこの CVE をどちらの PyPI パッケージにも紐付けておらず、pip-audit、Dependabot、Safety はこれらのバージョンを検出しない。
Python における CVE-2026-111497 の影響範囲
以下のパッケージのいずれかがインストールされている Python 環境があれば影響を受ける。
| パッケージ | 影響を受けるバージョン | 修正バージョン |
|---|---|---|
| Brotli (PyPI) | 1.2.0 以前 | 1.2.1 |
| brotlicffi (PyPI) | 1.2.0.x | 1.2.1.0 |
コードがこれらのパッケージを import している必要はない。以下の HTTP クライアントは Accept-Encoding: br を通知し、Brotli レスポンスを自動的にデコードする。
- urllib3(ひいては requests)。ただし Brotli または brotlicffi がインストールされている場合
- brotli extra を入れた httpx
- Brotli がインストールされている場合の aiohttp
- Scrapy、および上記のクライアントを利用するものすべて
攻撃者のデータがデコーダに届く経路は 2 つある。
- 外向きリクエスト。アプリが攻撃者の管理するサーバーから Brotli レスポンスを取得するケースで、webhook の配信、URL プレビュー、クローラー、「この URL を取得」機能などが該当する。
- 内向きリクエスト。フレームワークやミドルウェアが
Content-Encoding: br付きで送られたリクエストボディをデコードするケースで、Node.js における Express 5 の事例に相当する。
Python で CVE-2026-111497 を修正する方法
修正はパッケージのアップグレードで、手順は 4 つ。
- インストール済みのパッケージを
pip install -U "Brotli>=1.2.1"またはpip install -U "brotlicffi>=1.2.1.0"でアップグレードする。Poetry、uv、pip-tools のロックファイルを使っている場合は、制約を更新してロックファイルを再生成する。 - コンテナイメージと、どちらかのパッケージを同梱する wheel を再ビルドする。脆弱なバージョンでビルドしたイメージは、再ビルドするまで脆弱なまま残る。
- ラップトップ、CI ランナー、サーバー、コンテナなど、実行しているすべての環境を確認する。HTTP クライアントの extra 経由で Brotli が入るプロジェクトは多いので、解決済みの依存ツリー全体を見る。
- 当面は手動での確認に頼る。アドバイザリデータベースが CVE を PyPI パッケージに対応付けるまで、pip-audit、Dependabot、Safety はこれを報告しない。
Python の Brotli バインディングを PyPI ではなく Linux ディストリビューションのパッケージから導入している場合、修正はディストリビューション経由で提供される。そのセキュリティアドバイザリも確認してほしい。
Python の Brotli 脆弱性(CVE-2026-111497)とは
Python の Brotli 脆弱性とは CVE-2026-111497 を指す。PyPI 上の Python パッケージに影響する、Node2Shell として知られる Brotli デコーダの欠陥である。CVE レコードは CWE-252(戻り値の未チェック)と CWE-787(境界外書き込み)を組み合わせて記載している。
Python にとって CVE-2026-111497 はどれほど深刻か、悪用はされているのか
CVE レコードはこの欠陥を CVSS 4.0 スコア 9.2 と評価しており、Node.js も高深刻度としている。OSM は Brotli 1.2.0 と 1.2.1 を AddressSanitizer 付きでビルドし、細工したストリームを両方に通した。バージョン 1.2.0 は約 23 MB のストリームをすべて消費しても、入力をさらに要求し続けた。ストリームを一括で渡しても、1 バイトずつのチャンクで渡しても同じだった。バージョン 1.2.1 は毎回エラー -17 でストリームを拒否した。
OSM は Python 拡張におけるメモリ破壊やコード実行を追求していない。デコーダのコードは、研究者が未改変の Node.js 24.22.0 ビルドに対して悪用したものと同じコードだと、Impervaほかが報じている。Node.js については、The Hacker News が 10 月 22 日時点で実環境での悪用は確認されていないと伝えた。
それでも緊急案件として扱うべきだ。信頼できないネットワーク入力を受け付けるコンポーネントのメモリ安全性の欠陥であり、修正は定例のバージョンアップで済む。外部サーバーを呼び出すサービスや、圧縮されたリクエストボディを受け取るサービスから先に対応する。
Python アプリが影響を受けるか確認する方法
- 各環境で
pip show Brotli brotlicffi、各コンテナイメージでdocker run --rm <image> pip show Brotli brotlicffiを実行し、インストール済みのバージョンを確認する。 - 何がこれらのパッケージを引き込んでいるかを突き止める。
pipdeptree -r -p Brotliを実行して、どの依存関係が要求しているかを見る。ロックファイルはgrep -i brotli poetry.lock uv.lock requirements*.txtで検索する。 - 管理下にないサーバーへの外向き HTTP 呼び出しと、
Content-Encoding: brのリクエストボディをデコードするエンドポイントを洗い出す。 - 手順 3 に該当するサービスから先にアップグレードし、その後で残りを更新する。
Python からこのバグを再現する場合、brotli.decompress() はどんなエラーでも汎用的な brotli.error: decoder failed を送出するため、どのエラーコードが発生したのか分からない。細工したストリームを少しずつ流し込む Decompressor() は、1.2.0 では決して終了しない。
FAQ
Python で CVE-2026-111497 を修正するのはどのバージョンか?
Brotli 1.2.1 と brotlicffi 1.2.1.0、およびそれ以降のリリース。
影響を受けるにはコード内で Brotli をインポートする必要があるか?
パッケージがインストールされていれば十分だ。urllib3、requests、httpx、aiohttp は、Brotli か brotlicffi のどちらかが存在すれば自動的にそれを使い、アプリが呼び出すあらゆるサーバーからの Brotli レスポンスをデコードする。
pip-audit や Dependabot はこれを検出するか?
現時点では検出しない。10 月 23 日時点で、CVE レコード、OSV、GitHub Advisory Database のいずれにも両方の PyPI パッケージは掲載されていない。OSM は PYSEC エントリと、GitHub アドバイザリに対する PyPI パッケージのマッピングを提出し、ツールがこれを拾えるようにしている。
回避策はあるか?
Brotli と brotlicffi をアンインストールすれば脆弱なデコーダがなくなり、HTTP クライアントは gzip と deflate にフォールバックする。エッジで Brotli エンコードされたリクエストを拒否すれば受信側の露出は減るが、アプリが取得する Brotli レスポンスに対しては防御にならない。