戻る
2026/10/28
Node2Shell(CVE-2026-111497):影響を受けるシステムと今すぐ取るべき対策
Brotli の脆弱性 CVE-2026-111497 で実際にリスクがあるシステム、ケースごとの緊急度、パッチ適用・再ビルド・再起動・緩和策の手順を解説します。
2026年10月27日更新
CVE-2026-111497(通称「Node2Shell」または「HTTP2Shell」)は、Brotli 伸長処理(デコーダー)におけるメモリ破壊の脆弱性です。Brotli は Web 全体で使われている br 圧縮方式です。この不具合は Google の Brotli ライブラリのバージョン 1.0.3 から 1.2.0 に存在します [1]。Node.js はこのライブラリを同梱しており、Node.js プロジェクトは 22.x、24.x、26.x の各系列についてこの問題の深刻度を High と評価しています [2]。同じデコーダーは Python パッケージ、Linux のシステムライブラリ、デスクトップアプリ、開発者ツールにも含まれているため、実際の影響範囲は「Node.js サーバー」よりはるかに広くなります。
本記事は、自社が影響を受けるかどうか、まず何をすべきかを迅速に判断する必要があるチームを対象としています。
結論:自社の管理外にある相手(インターネット上のクライアント、外部 Web サイト、Webhook の送信元、アップロードされたファイルなど)から届く Brotli データを伸長するシステムが一つでもあれば、緊急案件として扱ってください。パッチを適用し、再ビルド・再起動を行い、それまでの間は br をブロックしてください。
脆弱性の内容
デコーダーは、圧縮ストリーム内の不正な「ブロックスイッチ」を正しく処理できません。このエラーを「データが不正である」ではなく「入力がさらに必要である」と扱い、小さな固定長の内部バッファーにバイトを追記し続け、最終的に末尾を越えて書き込んでしまいます [2]。細工した Brotli ストリームをアプリケーションに伸長させることができる攻撃者は、プロセスのメモリを破壊できます。その結果、次のような事態につながる可能性があります。
- クラッシュ(サービス拒否)。これが最も確実に起こる結果です。
- プロセスメモリの漏えい。レスポンスやログに、シークレット、トークン、他ユーザーのデータの断片が露出するおそれがあります。
- リモートコード実行の可能性。Node.js は想定される影響として RCE を挙げています [2]。最初に公開された概念実証(PoC)でコード実行に至ったのは、意図的に弱体化させたビルドに対してのみでしたが、その後研究者により、改変されていない公式の Node.js 24.22.0 ビルドに対しても、確実性は低いもののコード実行が報告されています [3]。
認証は不要で、攻撃者はデコーダーに届くバイト列を送り込むだけで済みます。そのため CVSS 4.0 のスコアは 9.2(Critical)となっています [1]。したがって、各システムについて問うべきは「Brotli を使っているか」ではなく、「信頼できない相手に Brotli を伸長させられる可能性があるか」です。
代表的な利用ケースとリスク
ケース 1:圧縮されたリクエストボディを受け付けるインターネット公開 API(最優先)
Node.js の API サーバー、BFF、API ゲートウェイ、アップロード用エンドポイントの中には、Content-Encoding: br 付きで送られたリクエストボディを伸長するものがあります。ミドルウェア経由で同じ処理を行うものもあります。リスク:インターネット上の匿名クライアントであれば誰でも細工したボディを送信できます。影響は、サービスを繰り返しクラッシュさせる低コストな DoS から、セッションデータや API キーを保持するプロセスからのメモリ漏えいまで多岐にわたります。緊急度:緊急。本日中にパッチを適用し、適用が完了するまではエッジで br のリクエストボディをブロックしてください。
ケース 2:外部からコンテンツを取得するサービス(高優先度)
Webhook の受信側、クローラーやスクレイパー、リンクプレビューや RSS のサービス、決済や SaaS との連携、Web を閲覧する AI エージェントは、いずれも外向きの HTTP リクエストを送信します。多くの HTTP クライアントは Accept-Encoding: br を送信し、レスポンスを自動的に伸長します。Python では、urllib3 と requests は Brotli または brotlicffi パッケージがインストールされていれば、コードで一度も import していなくてもこれを行います。aiohttp も同様で、httpx は brotli extra 付きでインストールされている場合に同様の動作をします [4]。リスク:悪意のある、侵害された、またはなりすましのリモートサーバーが、レスポンスを通じてバックエンドを攻撃できます。攻撃者が自社ネットワークに到達する必要はまったくありません。こちらから相手を呼び出すからです。緊急度:高。接続先が完全には信頼できない箇所から優先してパッチを適用してください。
ケース 3:ランタイムを内蔵したデスクトップアプリ、AI コーディングエージェント、CLI
Electron アプリ、Bun や Node ベースの CLI、AI 開発者ツールは、独自のランタイムのコピーを持っています。システムの node パッケージを更新しても、これらは修正されません。ディスク上のアプリを更新しても、すでに実行中のコピーは修正されません。長時間稼働するプロセスは、再起動するまで古いランタイムをメモリ上に保持し続けるためです。リスク:これらのツールは認証情報を保持し、外部コンテンツを取得することが多いため、ケース 2 と特権プロセスの組み合わせになります。緊急度:信頼できないコンテンツを取得するツールについては高。更新したうえで、確実に再起動してください。「更新したのに古いコードが動き続けている」という落とし穴については、HTTP2Shell:バイナリを更新しても実行中のプロセスは修正されない理由で詳しく解説しています。
ケース 4:コンテナイメージと CI/CD の成果物
修正前に FROM node:22、node:24、node:26 でビルドされたイメージには、ホストにパッチを適用していても脆弱なランタイムが残っています。同梱された Python wheel やベンダリングされた依存関係も同様です。リスク:イメージを再ビルドするまで、デプロイやオートスケーリングのたびに脆弱なコードが復活します。緊急度:ケース 1 および 2 の背後にあるイメージについては高。再起動だけでなく再ビルドを行ってください。
ケース 5:Linux のシステムライブラリ、フォント、画像処理
ディストリビューションはデコーダーを共有ライブラリとして提供しています(例:Ubuntu/Debian の libbrotli1)。これは、圧縮が有効な場合の curl および libcurl、WOFF2 Web フォント用の FreeType で使用されるほか、Pillow などの画像・ドキュメント処理ツールからも間接的に使用されます。リスク:ユーザーがアップロードしたフォントやドキュメントをレンダリングするシステムや、curl --compressed で外部コンテンツを取得するシステムには、信頼できない Brotli データが届く可能性があります。外部データをこれらのライブラリに一切渡さないサーバーであれば、実質的な影響は小さくなります。緊急度:多くの場合は中ですが、ドキュメントのレンダリングやアップロード処理を行うサービスについては高です。Ubuntu は 22.04、24.04、26.04、26.10 向けに修正済みの brotli パッケージを公開しています [1]。RHEL、Oracle Linux、その他のディストリビューションについては、状況を推測せず、brotli パッケージに関するベンダーのアドバイザリを確認してください。
ケース 6:信頼できる入力のみを扱う内部システム(低優先度)
内部キャッシュや自社のビルド成果物など、自社で生成したデータからのみ Brotli を伸長するサービスもあります。これらのリスクは低いもののゼロではありません。すでに足掛かりを得た攻撃者が、この脆弱性を使ってさらに侵入を拡大できるからです。緊急度:次回の定期サイクルでパッチを適用してください。
対応手順
ステップ 1:Brotli がデコードされている箇所を特定する(本日中)
- Node.js:すべてのホスト、すべてのコンテナイメージと CI ランナーで
node -vを確認します。コードと設定ファイルからbrotliDecompress、createBrotliDecompress、およびbrを伸長するボディ解析ミドルウェアを検索します。 - 内蔵ランタイム:使用中の Electron アプリ、Bun/Node CLI、AI エージェントを一覧化し、アプリのバージョンだけでなく、それぞれが内蔵するランタイムのバージョンを記録します。
- Python:各環境とイメージで
pip show Brotli brotlicffiを実行します。ロックファイルや SBOM でhttpx[brotli]や推移的な依存関係を確認します。 - OS パッケージ:
dpkg -l | grep brotliまたはrpm -qa | grep brotliを実行し、実際にライブラリを読み込んでいるプロセスを確認します。 - 上記のケースに基づいて優先順位を付けます。信頼できない入力が届く可能性があるもの(ケース 1、2、3、およびアップロードを扱うケース 5)を最優先とします。
ステップ 2:影響を受けるコンポーネントにパッチを適用する
- Node.js:22.23.4、24.22.1、26.12.1 以降にアップグレードします [2]。
- Python:
Brotli>=1.2.1またはbrotlicffi>=1.2.1.0。ロックファイルを再生成します [4]。 - アップストリームの Brotli/ベンダリングされた C コード:ブランチに応じて 1.0.10、1.1.1、1.2.1 を使用します [1]。
- OS パッケージ:ディストリビューションが提供する
brotli/libbrotliのセキュリティアップデートを適用します。 - デスクトップアプリとエージェント:修正済みランタイムを含むと明記されたベンダーのリリースに更新します。ベンダーから何も公表されていない場合は、そのアプリを安全とみなさず、未検証として扱ってください。
ステップ 3:再ビルド、再デプロイ、再起動を行う
- パッチ適用済みのベースイメージからコンテナイメージを再ビルドし、再デプロイします。古いイメージを再起動しても効果はありません。
- 脆弱なライブラリを読み込んでいた長時間稼働プロセスをすべて再起動します。対象は Node サービス、ワーカー、エージェントのセッション、システムライブラリにリンクしているあらゆるものです。ステートフルなジョブや AI エージェントについては、キューに入ったイベントや承認を失わないよう、先に処理をドレインするか引き継いでください。
ステップ 4:パッチ適用中に緩和策を講じる
- 受信側:リバースプロキシ、ロードバランサー、または WAF で、
Content-Encodingにbrを含むリクエストボディを、デコーダーに渡る前に拒否します。 - 送信側:
Accept-Encodingからbrを外すだけでは不十分です。悪意のあるサーバーはそれでもbrを送信できるためです。Content-Encoding: br付きで届いたレスポンスも拒否するか、デコードしないようにしてください [4]。 - Python での代替策:アップグレードを待たざるを得ない場合は、
Brotliとbrotlicffiをアンインストールし、クライアントがbrをデコードしないようにします。サーバーによってはそれでもbrを送信してくるため、事前にテストしてください。
ステップ 5:検証し、悪用の兆候を監視する
- ランタイムのバージョンは、パッケージマネージャーだけでなく、実行中のプロセスやコンテナの内部から確認します。
- イメージと SBOM を再スキャンし、古いコピーが推移的に取り込まれていないことを確認します。
brを扱うサービスについて、原因不明のクラッシュ、セグメンテーションフォールト、再起動ループがないか最近のログを確認します。単一の送信元からクラッシュが集中している場合は、攻撃の試みとして調査する価値があります。- 影響の大きいサービスがパッチ適用前に予期せずクラッシュしていた場合は、メモリ漏えいの可能性を否定できないため、そのプロセスが保持していたシークレットのローテーションを検討してください。
まとめ
| 状況 | リスク | 対処 |
|---|---|---|
公開 API が br のリクエストボディをデコードしている | 重大 | 直ちにパッチを適用し、エッジで br をブロック |
| バックエンドが外部 URL、Webhook、Web ページを取得している | 高 | 直ちにパッチを適用し、br レスポンスを拒否 |
| ランタイムを内蔵した Electron アプリ、AI エージェント、CLI | 高 | 更新し、実行中のすべてのインスタンスを再起動 |
| 古いコンテナイメージと CI の成果物 | 高 | パッチ適用済みのベースから再ビルドし、再デプロイ |
アップロード、フォント、curl --compressed で使われるシステムライブラリ | 中~高 | OS アップデートを適用し、ライブラリを読み込むサービスを再起動 |
| 信頼できる内部データのみ | 低~中 | 次回のサイクルでパッチを適用 |
パッケージへのパッチ適用は作業の半分にすぎません。実行中のプロセス、イメージ、内蔵ランタイムのいずれもが、古いコードで信頼できない Brotli をデコードできない状態になって初めて、リスクは解消されます。
Global
Korea
China
Taiwan
Vietnam
Thailand
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia