Brotli の脆弱性 CVE-2026-111497(Node2Shell/HTTP2Shell)の影響確認と対処手順
Node.js・Python・Bun・Envoy の修正版と、パッチ前の緩和策
Brotli デコーダの脆弱性 CVE-2026-111497(HTTP2Shell)は、細工した圧縮データで境界外書き込みを起こし、RCE に至る恐れがある。Node.js・Python・Bun・Envoy の修正版、確認コマンド、パッチ前の緩和策、スキャナの検出漏れ、時系列、FAQ まで整理する。
CVE-2026-111497 は、Google の Brotli デコーダ(1.0.3〜1.2.0)にある、細工した圧縮データで境界外書き込みを起こせる脆弱性で、Node.js の開示では「Node2Shell」、HTTP を扱うライブラリ全般に影響が広がってからは「HTTP2Shell」と呼ばれている。Brotli を使って HTTP の応答や要求を展開する Node.js・Python・Bun・Envoy・Istio・curl などが対象で、まず自分の環境の Brotli のバージョンと、それを呼び出す経路を確認し、修正版(libbrotli 1.2.1、Node.js 22.23.4/24.22.1/26.12.1 など)へ更新する必要がある。
本記事は、2026年10月21日〜24日に公開された Aikido Security の解説記事と、Node.js の2026年10月セキュリティリリースに関する報道をもとに、影響を受けるかどうかの確認手順、言語・基盤ごとの対処、パッチを当てられない間の緩和策を整理したものである。バージョン番号と日付は上記の出典で確認できた範囲に限り、不明な点は「公式発表を確認」と書く。CVSS は出典によって評価が異なり、Aikido の記事では CVSS v4.0 で 9.2(Critical)、Node.js 側は High としている。
3行でわかる要点
- 何が: Brotli デコーダの DecodeBlockTypeAndLength() が戻り値の処理を誤り、細工したストリームでメモリの境界外書き込みが起きる。影響はクラッシュ、メモリ漏えい、メモリ破壊、任意コード実行の可能性まで
- 誰が: Brotli を含む環境で、外部から受け取った Brotli 圧縮データを展開する処理がある人。サーバへの Content-Encoding: br のリクエストも、外部サーバから取得する br の応答も入口になる
- 何をする: 利用中のランタイムとパッケージを確認して修正版へ更新する。更新できない間は Brotli のデコードを止める。依存スキャナは PyPI の Brotli を検出しない場合があるため、自分で確認する
影響範囲の早見表
出典で確認できた影響版と修正版を、製品ごとにまとめる。OS ベンダーのパッケージは、バージョン番号を変えずに修正だけを取り込む(バックポートする)場合があるため、番号が古く見えても修正済みのことがある。逆に、番号だけで安全と判断せず、ディストリビューションのセキュリティ情報を見る。
| 製品 | 影響を受ける版 | 修正版 |
|---|---|---|
| Google Brotli(libbrotli) | 1.0.3〜1.2.0(全プラットフォーム) | 1.2.1(旧系は 1.0.10/1.1.1) |
PyPI Brotli | 1.2.0 以前 | 1.2.1 |
PyPI brotlicffi | 1.2.0.x | 1.2.1.0 |
| Node.js | 22・24・26 系の修正前の版(実証は 24.22.0) | 22.23.4/24.22.1/26.12.1。Node.js 20 以前は修正なし |
| Bun | 1.4.4 より前 | 1.4.4 |
| Envoy | 修正前の各系 | 1.40.0/1.39.3/1.38.6/1.37.8(1.36.12 にも含まれるが 1.36 はサポート外) |
| Istio | 修正前の各系 | 1.30.6/1.31.2(1.29.9 もあるが 1.29 は EOL) |
| curl/libcurl | Brotli に依存する構成 | Brotli 側の更新(1.2.1、パッチ済みの旧版、ディストリビューションのパッケージ) |
| Apache/Nginx | デフォルトでは Brotli をデコードしないため通常は対象外 | 標準の mod_brotli もデコードはしない |
表の「Bun より前」「Envoy の修正前の各系」などは、出典に個別の影響版の下限が明記されていないものである。厳密な範囲は各プロジェクトの公式アドバイザリを確認してほしい。Python の公式アドバイザリは GHSA-9v8h-qqgm-4m35 である。
何が起きているのか — 脆弱性の仕組み
Brotli は HTTP の Content-Encoding: br で使われる圧縮方式で、gzip より小さくなるため、ブラウザや CDN、API サーバで広く使われている。問題は展開(デコード)側にある。Google Brotli のデコーダには、ブロックの種類と長さを読み取る DecodeBlockTypeAndLength() という関数があり、この関数は bool を返す。ところが、戻り値の false が「ストリームが不正」という意味と「入力がまだ足りない」という意味の両方に使われており、呼び出し側が2つを区別できない。さらに高速パスでは、この戻り値そのものが捨てられていた。CWE の分類では、戻り値を確認しない CWE-252 と、境界外書き込みの CWE-787 の組み合わせである。
攻撃者は、あり得ないブロックの切り替えを強制するストリームを作る。デコーダは不正を検知できないまま、古いブロックの状態を使ってデコードを続け、確保したバッファの外へ書き込む。結果として、プロセスのクラッシュ(サービス拒否)、メモリの漏えい、メモリの破壊、条件が揃えば任意コードの実行にまで至る可能性がある。実際の悪用のしやすさは、メモリの配置や OS の防御機構、ランタイムの実装に依存するため、すべての環境で同じ結果になるとは限らない。
上流の修正は google/brotli のコミット 0ed4268 で、エラーコード BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH(値は -17)を追加し、不正なブロック切り替えを明示的にエラーとして扱う。つまり、これは Node.js や Python 固有のバグではなく、Brotli のコードを使うすべての製品が共通して抱えていた問題である。この構造が、通称が Node2Shell から HTTP2Shell へ広がった理由でもある。
攻撃経路 — 受信側にも送信側にも入口がある
出典は、攻撃が双方向で成立するとしている。「自分のサーバが攻撃される」場合だけでなく、「自分のプログラムが悪意あるサーバへ接続する」場合も該当する点が、見落としやすい。
- インバウンド(受信側): Content-Encoding: br のリクエストボディをデコードするアプリやミドルウェア。出典は Node.js の Express 5 を例に挙げている。攻撃者は細工した Brotli のボディを POST するだけでよい
- アウトバウンド(送信側): 悪意あるサーバが返した Brotli のレスポンスを、自分のプログラムが取得してデコードする場合。Webhook の受信確認、URL のプレビュー(リンクのサムネイル取得)、クローラ、外部 API 連携、社内の SSRF 的な取得機能などが該当する
- 間接的な経路: アプリ自体は Brotli を意識していなくても、HTTP クライアントのライブラリが Brotli パッケージを見つけて自動的に有効化する場合がある。Python の urllib3(requests 経由を含む)、httpx(brotli extra)、aiohttp、Scrapy がこれに当たる

Python では特に、依存関係の奥で Brotli が入っているだけで、HTTP クライアントが Accept-Encoding に br を付け、レスポンスを展開してしまう。Brotli パッケージは月間約8,280万回ダウンロードされており、直接入れた覚えがなくても、他のパッケージの依存として入っていることが多い。
なお、野良の悪用報告は、2026年10月22日時点では確認されていない。一方で、Imperva などの研究者が、修正前の Node.js 24.22.0 で悪用できることを研究デモとして示している。デモが公開されている以上、悪用コードが広まるまでの時間は短いとみて、対応は急いだほうがよい。
自分が影響を受けるかの確認手順
手順は、「どのランタイムのどの版を使っているか」「Brotli パッケージが入っているか」「外部のデータを Brotli で展開する経路があるか」の3段階で見る。まず Python 環境のパッケージを確認する。コンテナの場合は、実行中のイメージの中を確認するのが確実である。
# 1. Python 環境にある Brotli 系パッケージとバージョン
pip show Brotli brotlicffi
# 2. コンテナイメージの中を確認する(イメージ名は置き換える)
docker run --rm <image> pip show Brotli brotlicffi
# 3. 何が Brotli を連れてきているか(依存の逆引き)
pipdeptree -r -p Brotli
# 4. ロックファイルや requirements に含まれていないか
grep -i brotli poetry.lock uv.lock requirements*.txtNode.js は、ランタイムのバージョンと、同梱されている Brotli のバージョンを確認する。process.versions.brotli は Node.js が内蔵する Brotli のバージョンを返すプロパティである。ただし、Node.js のバージョンが修正版かどうかを一次の判断材料にし、同梱 Brotli の番号は補助として見る。
# Node.js のバージョン(修正版: 22.23.4 / 24.22.1 / 26.12.1)
node -v
# Node.js に同梱されている Brotli のバージョン
node -p process.versions.brotli次に、外部から受け取ったデータを Brotli で展開する経路があるかを、設計面から洗い出す。確認する観点は次の通りである。
- 公開しているサーバが、Content-Encoding: br のリクエストを受け付けて展開しているか(Express 5 のボディパーサ、API ゲートウェイ、Envoy/Istio のフィルタ)
- 外部の URL にアクセスする機能があるか(Webhook の送信、URL プレビュー、画像取得、クローラ、外部 API 連携)
- その HTTP クライアントが、Accept-Encoding に br を付けるか(ライブラリの既定値を確認する)
- 同じ Brotli ライブラリを、複数のコンテナイメージ、サーバレス関数、CI のランナーが別々に抱えていないか
言語・基盤別の対処
Node.js
Node.js は、2026年10月のセキュリティリリース(10件の脆弱性を修正、うち High が4件)でこの問題を修正した。修正版は 22.23.4、24.22.1、26.12.1 である。Node.js 20 以前の系統には修正が提供されないため、20 以前を使っている場合は、サポート対象の系統(22 以上)へ移行するしかない。移行がすぐにできない場合は、後述する緩和策(br のリクエストの拒否、外部への br の無効化)で当面をしのぐ。
あわせて、Node.js 自体だけでなく、Docker イメージのベース(node:22 などのタグ)が古いままになっていないかも確認する。タグが同じでも、ビルド済みのイメージは古い Node.js を含んだまま残っていることがある。イメージを再ビルドし、デプロイし直して初めて修正が反映される。
Python
PyPI の Brotli は 1.2.0 以前、brotlicffi は 1.2.0.x が影響を受け、修正版はそれぞれ 1.2.1、1.2.1.0 である。requirements やロックファイルで固定している場合は、固定値を上げてロックを再生成し、コンテナイメージを再ビルドする。urllib3、httpx、aiohttp、Scrapy は、Brotli のパッケージが環境にあれば自動的に利用するため、これらのライブラリ側は更新しなくても、Brotli のパッケージを更新すれば対処になる。
# 修正版へ更新(環境に合わせて pip / uv / poetry のいずれか)
pip install -U "Brotli>=1.2.1" "brotlicffi>=1.2.1.0"
# 更新後に確認
pip show Brotli brotlicffiここで注意したいのは、Python の依存解析ツールの多くが、この問題を検出しないことである(後述)。Brotli は C のコードを内包したホイールとして配布されるため、システム側の libbrotli とは別に、パッケージの中に独自のコピーを持つ。OS のパッケージを更新しただけでは、Python の仮想環境の中の Brotli は更新されない。
Bun
Bun は 1.4.4 で修正された。bun upgrade で更新し、CI やコンテナのイメージに固定している Bun のバージョンも合わせて上げる。
Envoy・Istio
Envoy は 1.40.0、1.39.3、1.38.6、1.37.8 で修正された。1.36.12 にも修正は含まれるが、1.36 系はすでにサポート対象外である。Istio は 1.30.6 と 1.31.2 が修正版で、1.29.9 もあるが、1.29 系は EOL である。サービスメッシュや API ゲートウェイでは、プロキシが Brotli の展開(decompressor フィルタ)を有効にしている場合に影響する。設定でそのフィルタを使っていないなら影響は限定的だが、使っているかどうかを設定から確認してから判断する。
curl・OS のパッケージ
curl と libcurl は、Brotli ライブラリを外部の依存として使う。そのため、更新の対象は curl 本体ではなく、リンクされている Brotli である。libbrotli の 1.2.1、パッチ済みの旧系(1.0.10、1.1.1)、またはディストリビューションが提供する修正済みパッケージに更新する。Debian 系、RHEL 系、Alpine などでは、バージョン番号が変わらずに修正だけが取り込まれることがあるため、各ディストリビューションのセキュリティトラッカーで CVE-2026-111497 の扱いを確認する。静的リンクした自作のバイナリや、Brotli を同梱したアプリは、OS の更新では直らないので、ビルドし直す必要がある。
パッチを当てられない間の緩和策
修正版が使えない(Node.js 20 以前、検証に時間がかかる、ベンダーの更新待ちなど)場合は、Brotli のデコードを使わないようにして、攻撃の入口を塞ぐ。ただし、これらは根本的な修正ではなく、他のランタイムが同梱するデコーダには効かない。恒久対応は修正版への更新である。
Python の緩和策
- Brotli と brotlicffi をアンインストールする。HTTP クライアントは gzip/deflate にフォールバックするが、すべてのライブラリで動作が保証されるわけではないので、動作を確認する
- httpx[brotli] などの extra を依存から外し、ロックファイルを再生成する
- 環境を再起動(またはコンテナを再デプロイ)して、読み込み済みのモジュールを入れ替える
- 他のランタイム(Node.js など)が同梱するデコーダは残るので、Python だけの対処で終わらせない
インバウンド(受信側)の緩和策
プロキシ、ロードバランサ、またはアプリのミドルウェアで、Content-Encoding に br を含むリクエストを拒否する。判定は大文字小文字を区別せず、gzip, br のようにリスト内に含まれる場合も対象にする。ヘッダの値を単純な完全一致で比較すると、BR や gzip, br をすり抜けられてしまう。通常の API クライアントがリクエストボディを Brotli で送ることはまれなので、拒否しても影響は小さいことが多い。
アウトバウンド(送信側)の緩和策
Accept-Encoding から br を外す。ただし、これだけでは不十分である。悪意あるサーバは Accept-Encoding を無視して Content-Encoding: br で応答できるため、クライアント側で br のレスポンスのデコードを無効化するか、br のレスポンスを拒否する必要がある。Webhook、URL プレビュー、クローラのように、相手先を自分で選べない機能から優先して対処する。
スキャナが検出しない問題への注意
2026年10月23日の時点で、pip-audit、Dependabot、Safety は、この CVE を PyPI の Brotli と brotlicffi に対応付けておらず、これらのツールではアラートが出ない。修正版のリリースノートにも CVE の記載がない。そのため、「スキャナが緑だから安全」とは言えない。上の確認コマンドで直接バージョンを見る、必要なら脆弱性データベースの対応付けが更新されるまで、手動の確認を運用に組み込む必要がある。
同じ構造の問題は、最近も起きている。パッケージそのものが改ざんされた LiteLLM 1.107.0 改ざん事件では、依存の確認を人が先回りして行う必要があった。また、PHPの緊急脆弱性 CVE-2026-109618/109619でも、ベンダーの情報とスキャナの検出にずれが生じる場面があった。脆弱性の公表とツールの検出の間には時差があり、その間は自分で確認する、というのが現在の前提になる。
発覚から現在までの時系列
| 日付 | 出来事 |
|---|---|
| 2026年2月 | OpenAI がこの問題を発見し、未認証のリモートコード実行として報告。ソースは修正されたが、セキュリティ問題とは認識されず、リリースは後日になった |
| 2026年10月21日 | Node.js が CVE を開示(10件の脆弱性を修正するリリース、うち High が4件) |
| 10月22日 | Python 側の修正。この時点で野良の悪用報告はなし |
| 10月23日 | 他の言語や HTTP アプリへ範囲が拡大。libbrotli、Python、C++、Node.js、Bun、Envoy の各パッチが公開 |
| 10月23日時点 | pip-audit、Dependabot、Safety は PyPI の Brotli に CVE を対応付けておらず、検出しない |
| 10月21〜24日 | Hacker News で話題になる(319 ポイント)。研究者が未改変の Node.js 24.22.0 で悪用を実証(研究デモ) |
OpenAI の開示は patchtheplanet.org/brotli で公開されている。詳細な技術的経緯や、悪用の最新状況は、公式の発表と各ベンダーのアドバイザリを確認してほしい。この記事に載せた状況は、2026年10月24日までに確認できた範囲のものである。
今日やることのチェックリスト
- 利用中の Node.js、Bun、Envoy/Istio、Python の Brotli のバージョンを洗い出し、上の早見表と照合する
- コンテナイメージの中身を確認する(ソースではなく、実際に動いているイメージ)
- 外部から受け取るデータを Brotli で展開する経路(Content-Encoding: br の受信、Webhook/URL プレビュー/クローラ)を洗い出す
- 修正版へ更新し、イメージを再ビルドして、再デプロイする。ロックファイルも再生成する
- 更新できないものには、br のリクエスト拒否と、外向きの br の無効化を入れる
- スキャナの結果を信用せず、確認コマンドの出力をチケットや記録に残す
よくある質問
CVE-2026-111497 は何が原因ですか。
Google Brotli のデコーダ(1.0.3〜1.2.0)の DecodeBlockTypeAndLength() が、戻り値で不正なストリームと入力不足を区別できず、高速パスでは戻り値が捨てられていたことです。細工したストリームで不可能なブロック切り替えが起き、古いブロックの状態のままデコードが続いて境界外書き込みになります。
Node2Shell と HTTP2Shell は別の脆弱性ですか。
同じ CVE-2026-111497 の通称です。Node.js 側の開示で Node2Shell と呼ばれ、その後 HTTP を使うライブラリやアプリ全般に影響が広がったため、HTTP2Shell とも呼ばれるようになりました。
Nginx や Apache を使っていれば影響を受けますか。
Apache と Nginx は、デフォルトでは Brotli をデコードしません。Apache の標準の mod_brotli もデコードはしないので、通常は対象外です。ただし、同じサーバ上で動く Node.js や Python のアプリが Brotli を展開しているなら、そのアプリは影響を受けます。
pip-audit や Dependabot が何も出さなければ安全ですか。
安全とは言えません。2026年10月23日の時点で、pip-audit、Dependabot、Safety は PyPI の Brotli や brotlicffi にこの CVE を対応付けておらず、検出しません。pip show でバージョンを直接確認してください。
Node.js 20 を使っています。どうすればよいですか。
Node.js 20 以前には修正が提供されません。サポート対象の 22 以上へ移行するのが恒久的な対処です。すぐに移行できない間は、Content-Encoding に br を含むリクエストの拒否や、外向きの br の無効化で入口を塞いでください。
Accept-Encoding から br を外せば十分ですか。
十分ではありません。悪意あるサーバは Accept-Encoding を無視して br で応答できるため、クライアント側で br のレスポンスのデコードを無効化するか、拒否する必要があります。
すでに悪用されていますか。
2026年10月22日時点で、野良の悪用報告は確認されていません。一方で、Imperva などの研究者が、修正前の Node.js 24.22.0 で悪用できることを研究デモとして示しています。最新の状況は公式発表を確認してください。
この記事に関連する無料ツール(登録不要・その場で結果)
お気軽にご相談ください
お問い合わせ