
PHP2Shellの次はNode2Shell。同じ「〜2Shell」でも、直す人と塞げる場所が違う
PHP2Shellの修正版が出た同じ日に、Node.jsも定例のセキュリティリリースを出していた。その中のBrotli展開の脆弱性CVE-2026-111497が、翌日には「Node2Shell」と呼ばれ始める。さらにPythonやプロキシにも波及していると分かり、24日には「HTTP2Shell」という呼び名も出てきた。
先に結論を書いておく。名前は似ているが、中身はかなり違う。PHP2Shellは、ディストリやホスティング事業者がPHPを更新すればほぼ片付く。Node2Shellは、自分のイメージや依存の中に同じBrotliがいくつ入っているかを数えるところから始まる。
この記事は10月24日昼(日本時間)までの情報で書いている。
何が起きたか(日本時間)
2月27日:上流のGoogle Brotliに修正のコミットが入る。メッセージは「Detect and report invalid stream earlier.」で、セキュリティの修正だとは書かれていない
10月14日:Node.jsが事前告知。最高の深刻度は「HIGH」とだけ書かれていた
10月21日19時39分:Node.js 22.23.4 / 24.22.1 / 26.12.1 をリリース
10月22日早朝:上流Brotliが 1.2.1 / 1.1.1 / 1.0.10 を公開
10月22日21時22分:Imperva が「Node2Shell」と題した分析を公開
10月22日22時35分:CVEレコード公開。CVSS 4.0で9.2
10月22〜23日:PythonのBrotli、Bun、Envoy、Istioが相次いで修正版やアドバイザリを出す
10月23日23時1分:Node.js公式ブログに、発動の条件の説明が追加される
10月24日:「HTTP2Shell」の呼び名が出回り始める

HTTP2Shellは同じCVEの別名で、別の番号は振られていない。HTTP/2というプロトコルの問題でもない。HTTPでBrotliを展開するソフト全般が対象になる、という意味の呼び名だ。
原因は上流のBrotliにあった
バグは上流Brotliの展開処理(c/dec/decode.c)にある。壊れたデータを受け取ったときに、本来は「形式エラー」として止めるべきところを「入力がもっと要る」と扱ってしまう。Node.js公式の説明はこうだ。
An invalid block switch was reported as a temporary need for more input instead of a permanent format error, so the streaming decoder kept appending input bytes to an eight-byte internal buffer.
自分の訳では「無効なブロック切替が、恒久的な形式エラーではなく一時的な入力不足として報告された。そのためデコーダは、8バイトの内部バッファに入力を追記し続けた」となる。
結果は境界外書き込みで、クラッシュやメモリの漏えいに加えて、RCEに至るおそれがある。影響を受けるのはBrotli 1.0.3〜1.2.0で、Node.jsはこれを同梱していた。

どこが危ないか
条件は「攻撃者が用意したBrotliデータを展開すること」で、Webを処理するNodeが全部危ないわけではない。ただし経路が2方向ある。
受け取る側の代表は、Express 5(body-parser 2.x)だ。`express.json()` などは、`Content-Encoding: br` のリクエストを既定で展開する。Impervaは、公式の24.22.0のイメージでコード実行を確認したと報告している。成功までに何度か試す必要があったという。Express 4(body-parser 1.x)はbrを展開しない。素のhttpサーバーも、受け取っただけでは展開しない。
取りに行く側は `fetch()` だ。接続先が返したBrotliの応答を自動で展開する。Webhook、URLのプレビュー、クローラーのように、外部のURLを取りに行く処理が当てはまる。

Node.jsの外にも広がっている。PythonのBrotliとbrotlicffiは、入っているだけでurllib3やrequestsが自動で使う。Bunは1.4.4未満、EnvoyとIstioはBrotliの展開を設定している場合が対象だ。
Node 20以前は、今年4月30日にEOLを迎えていて修正は出ない。20.19.5が同梱するBrotliは1.1.0で、影響範囲に入っている。
PHP2Shellと比べる
時系列
PHP2Shellは情報がリークして、修正版が前倒しで出た。Amazonは公開の4日前に悪用の試みを観測している。Node2Shellは定例のリリースとして静かに出て、条件の説明は2日後に追加された。ほかの言語への波及は、そのあとから分かってきた。
原因
PHP2ShellはPHP本体(Zendエンジン)のメモリ管理の不備だった。Node2Shellは、同梱している上流ライブラリの不備だ。だからNode.jsを使っていなくても、同じBrotliを抱えていれば当てはまる。
対策
PHPは、ディストリやホスティング事業者が更新すれば大部分が終わる。CloudflareやAWS WAFも、修正版の公開の前後に専用のルールを出していた。
Nodeは直す人が多い。Node本体の更新に加えて、コンテナイメージの作り直しとPythonの依存の更新が要る。BunやEnvoyのような同梱製品は、それぞれの更新を待つことになる。24日昼の時点で、CloudflareとAWS WAFの変更履歴にはBrotli向けのルールが見当たらない。Vercelは、全プロジェクトで受信側の攻撃を止めるWAFルールを入れた。それでも、自分の関数が取りに行った応答は対象外だと明記している。
Only the runtime patch covers fetched responses.
自分の訳では「取得した応答を守れるのは、ランタイムの更新だけ」となる。WAFで塞げるのは受け取る側だけ、ということだ。
影響範囲
PHP2Shellは、Webリクエストを処理するPHPならほぼすべてが対象だった。Node2Shellは、Brotliを展開する経路に限られる。そのかわり受信と送信の両方向で、言語もまたぐ。
共通点もある。どちらもCISAのKEV(悪用が確認された脆弱性の一覧)には、24日4時30分の版で載っていない。侵害の確認も、国内外ともまだない(PHPでは原因のCVEを特定していない被害の公表が1件ある)。EOLの層が取り残される点も同じで、PHPは8.1以下、Nodeは20以下が該当する。

前の記事の訂正
10月22日のeMudhra証明書の記事では、このCVEについて「公式は発動の条件もCVSSも公開していない」と書いた。その後、条件の説明とCVSS 4.0の9.2が出ている。推測として書いた「外から受け取った圧縮データの展開が気になる」は、公式の説明で裏付けられた形になる。
今日やること
Step 1: Node本体の版を見る
node --version
docker run --rm <image> node --version22.23.4 / 24.22.1 / 26.12.1 以上なら本体は直っている。同梱Brotliの版の表記は、修正後も1.2.0のままだ。判断はNode本体の版で行う。`node:24.22.0` のように版を固定したイメージは、何度ビルドしても直らない。
Step 2: Express 5と、外部のURLを取りに行く処理を探す
npm ls express body-parser
grep -rnE "express\.json|createBrotliDecompress|brotliDecompress|fetch\(" src/Express 5を使っていて、すぐに更新できないなら、`express.json({ inflate: false })` で圧縮されたボディを拒否できる。gzipも一緒に拒否される点には注意したい。
Step 3: PythonのBrotliを確認する
pip show Brotli brotlicffiBrotli 1.2.1、brotlicffi 1.2.1.0 以上にする。直接入れた覚えがなくても、requestsやhttpxの依存で入っていることがある。
Step 4: プロキシと同梱製品を見る
EnvoyやIstioでBrotliの展開を有効にしているなら、修正版にするか展開を止める。Bunは1.4.4以上にする。
Step 5: すぐ更新できないなら、入口でbrを拒否する
リバースプロキシやLBで、`Content-Encoding` に `br` を含むリクエストを拒否する。これで塞げるのは受信だけで、`fetch()` の応答は守れない。
名前より、どこにあるかを数える
PHP2Shellの棚卸しでは「PHPがどこで動いているか」を数えた。今回数えるのは「Brotliのデコーダがどこにあるか」で、Node本体、イメージ、Pythonの依存、プロキシと場所が散らばっている。一つ直して終わり、とはいかない。
あなたの環境では、Brotliを展開している場所をいくつ見つけられただろうか。思わぬところに入っていた例があれば、コメントで教えてください。
この記事は10月24日昼の情報で書いている。Node.js公式や各ディストリ、JPCERT/CC・IPAの発表を、この記事より優先してほしい。
参考リンク
#Nodejs #Node2Shell #HTTP2Shell #PHP2Shell #Brotli #脆弱性 #セキュリティ #Express #Python #パッチ管理