「Node2Shell」「HTTP2Shell」と呼ばれ始めたBrotliの穴。Node.jsを使っていなくても、Pythonの中にいるかもしれない

Brotliの展開処理の穴(CVE-2026-111497)に、「Node2Shell」「HTTP2Shell」という呼び名が付きました。Express 5は初期設定のまま受信データを展開し、Pythonでは入っているだけでrequestsなどが使います。WAFで守れるのは受信側だけです。

この記事の結論

  1. Brotliの展開処理の穴(CVE-2026-111497)に、「Node2Shell」「HTTP2Shell」という呼び名が付いた。番号は同じ1つで、深刻度はCVSS 4.0で9.2
  2. Express 5は、Brotliで圧縮されたリクエストを初期設定のまま展開する。Pythonでは、部品が入っているだけでrequestsなどが自動で使う
  3. WAFで守れるのは受け取る側だけ。こちらから取りに行った応答は、本体の更新でしか守れない
  • Brotliの展開処理の穴(CVE-2026-111497)に、「Node2Shell」「HTTP2Shell」という呼び名が付いた。番号は同じ1つで、深刻度はCVSS 4.0で9.2
  • Express 5は、Brotliで圧縮されたリクエストを初期設定のまま展開する。Pythonでは、部品が入っているだけでrequestsなどが自動で使う
  • WAFで守れるのは受け取る側だけ。こちらから取りに行った応答は、本体の更新でしか守れない

先日、Brotliの「展開する側」の穴について書いた。その後、この穴に名前が付き、影響がNode.jsの外にも広がっていることが分かってきた。

個人のブログでこの経緯を丁寧に追った記事(zephel01さんのnote)があり、それを手がかりに、各社の一次情報を確かめた。分かったことを整理する。

2つの呼び名は、同じ穴

  • Node2Shell:セキュリティ会社のImpervaが、この穴の分析に付けた名前
  • HTTP2Shell:同じくAikidoが、Node.js以外にも広がっていると報告したときの呼び名

どちらもCVE-2026-111497の別名で、別の番号はない。HTTP2Shellは「HTTP/2」という通信方式の問題ではなく、HTTPでBrotliを展開するソフト全般が対象になりうる、という意味合いだ。

GitHubのアドバイザリでは、深刻度はCVSS 4.0で9.2(Critical)。影響を受けるのは、Google Brotliの1.0.3から1.2.0までだ。

原因は2月に直っていた

Aikidoによると、この穴はOpenAIが2月に見つけていた。Brotliのソースコードではそのとき原因が直されたが、セキュリティの問題だとは認識されず、修正を含む版も出ていなかった。

そのため今になって、Brotliを中に入れているソフトが、それぞれ自分で更新を出すことになった。Node.js、Bun、Envoy、Istio、Pythonの部品、curlなどだ。

SPONSORED

どこが危ないのか:2つの方向

危ないのは「攻撃者が用意したBrotliのデータを展開する」場所だ。Webを扱うNode.jsが全部危ないわけではない。ただし方向が2つある。

方向代表的な場所
受け取る側Express 5(body-parser 2.x)の express.json() など。Brotliで圧縮されたリクエストを初期設定のまま展開する
取りに行く側Node.jsのfetch()。取りに行った先が返したBrotliの応答を自動で展開する。Webhookの受け取り先への問い合わせ、URLのプレビュー、クローラーなど

Impervaは、公式のNode.js 24.22.0のイメージで、Express 5の受信と、fetch()の応答の両方から、送り込んだコードが実行されることを確かめた。成功までに何度か試す必要があったという。修正版の24.22.1では、同じデータは拒否された。

一方で、Impervaによると何もしない素のNode.jsのHTTPサーバーは、受け取っただけではBrotliを展開しない。Brotliの展開はbody-parserの2.0.0から入ったものだ。

Node.jsの外:Python

Aikidoが注意を呼びかけているのが、Pythonだ。

  • PythonのBrotliやbrotlicffiという部品が環境に入っていると、requests、httpx、aiohttpなどの通信の部品が自動でそれを使う
  • 自分で入れた覚えがなくても、ほかの部品の依存で入っていることがある
  • Brotli 1.2.1、brotlicffi 1.2.1.0 以上に上げる

Aikidoは、23日の時点では脆弱性のデータベースにPyPIの部品が結び付いておらず、pip-auditなどの検査ツールが警告を出さないと指摘していた。その後GitHubのアドバイザリには登録されたが、ツールの結果だけに頼らず、版を自分で確かめるほうが確実だ。

なお、Aikidoによると、ApacheとNginxは初期設定ではBrotliを展開しない。圧縮して送る機能とは別だ。

WAFで守れるのは、受け取る側だけ

Vercelは、全プロジェクトで受信側の攻撃を止めるWAFのルールを入れた。そのうえで、はっきりこう書いている。

取りに行った応答を守れるのは、ランタイムの更新だけだ(筆者訳)。

WAFは、外から入ってくる通信を見張る。自分のプログラムが外へ取りに行って受け取った応答は、その外側にある。だから本体の更新は避けられない。

Vercelはほかにも、次のように案内している。

  • Node.js 20はサポートが終わっていて、この修正は出ない。22か24に上げて、もう一度デプロイする
  • 自分で動かしているNext.jsは、画像の最適化でBrotliの応答を止めないので、Node.jsを上げる
  • 自分で作ったコンテナのイメージは、修正済みの土台で作り直す

PHP2Shellとの違い

PHP2ShellNode2Shell(HTTP2Shell)
原因PHP本体の不具合中に入れているBrotliという部品の不具合
主に直す人レンタルサーバーやOSの提供元が更新すれば、多くは片付く自分。本体、イメージ、Pythonの部品、プロキシと、場所が散らばる
範囲Webのリクエストを処理するPHPのほぼすべてBrotliを展開する経路だけ。そのかわり受信と送信の両方向で、言語もまたぐ
サポート切れの層PHP 8.1以下Node.js 20以下

PHP2Shellでは「PHPがどこで動いているか」を数えた。今回数えるのは「Brotliを展開する部品が、どこに入っているか」だ。

今日やること

  1. Node.jsの版を見る。22.23.4 / 24.22.1 / 26.12.1 以上なら本体は直っている。版を固定したイメージは、何度作り直しても直らないので、指定を上げる
  2. Express 5と、外へ取りに行く処理を探す。すぐ上げられないなら、Express 5は express.json({ inflate: false }) で圧縮されたリクエストを断れる(gzipも一緒に断る点に注意)
  3. Pythonの部品を見る。pip show Brotli brotlicffi で版を確かめ、1.2.1 / 1.2.1.0 以上に上げる
  4. プロキシと同梱の製品。EnvoyやIstioでBrotliの展開を使っているなら更新か停止。Bunは1.4.4以上に
  5. すぐ更新できないなら、入口で Content-Encoding: br を断る。ただし守れるのは受信だけ

Node.jsのバージョンの確かめ方は、ターミナルで次のとおり。

node --version
npm ls express body-parser
pip show Brotli brotlicffi

まとめ

  • 「Node2Shell」「HTTP2Shell」は、どちらもCVE-2026-111497。CVSS 4.0で9.2
  • 原因は2月に直っていたが、セキュリティの問題と認識されず、各ソフトが今になって更新を出している
  • Express 5の受信とfetch()の応答の両方で、コードの実行が確かめられた
  • Pythonは、部品が入っているだけでrequestsなどが使う。1.2.1 / 1.2.1.0 以上へ
  • WAFは受信だけ。取りに行った応答は本体の更新でしか守れない。Node.js 20には修正が出ない
SPONSORED

出典

本記事は2026年10月25日時点の公表内容に基づく。各ソフトの修正版は今後も追加される可能性がある。最新の情報は、使っているソフトの公式の発表で確認すること。

新しい記事が出たら、ブラウザの通知でお知らせします。

メールアドレスの登録は要りません。いつでも止められます。

AUTHOR

北海道のWEB屋

北海道を拠点に、Web業界14年・サポート実績1,000件以上。WordPressの復旧、サーバー移転、独自ドメインとメールの設定、PHP・JavaScriptの修正まで対応します。相談と見積もりは無料です。

SPONSORED

関連記事

RELATED