HTTP2Shellの確認方法:Claude Codeは2.1.308以上。n8n・Python・Node.jsで版表示を信じてはいけない場所

Claude Code 2.1.307の実行ファイルには「Bun v1.4.4」と記録されています。HTTP2Shellを直したBunの版です。ところが中身を調べると、Brotliの修正が入っていませんでした。修正が入ったのは2.1.308からです。

HTTP2Shell(CVE-2026-111497)で確認するべき版は次の4つです。Claude Codeは2.1.308以上、n8nは2.44.6以上(1.x系は1.123.87以上)、Node.jsは22.23.4・24.22.1・26.12.1以上、Pythonはbrotli 1.2.1・brotlicffi 1.2.1.0以上。ただし、見て確かめられる版の表記のうち2つは当てになりません。

10月25日に、私のMacと公開パッケージを実際に調べました。その結果をもとに、AIツールや自動化の環境で見る場所と、そのまま使える確認コマンドを載せます。

目次

HTTP2Shellは、圧縮されたデータを展開するだけで当たる

HTTP2Shellは、Googleの圧縮形式Brotliの展開処理にある欠陥の通称です。CVEの記録では、影響を受けるのはBrotli 1.0.3〜1.2.0、深刻度はCVSS 4.0で9.2です。名前に「HTTP2」と入っていますが、HTTP/2プロトコルとは関係ありません。

最初に修正版を出したのはNode.jsです。10月21日のセキュリティリリースでは、細工した圧縮データを展開すると8バイトの内部バッファの外へ書き込み、プロセスの停止やメモリ内容の漏えい、遠隔からのコード実行につながるとしています。報告者はOpenAI Codex Securityです。

当初は「Node2Shell」と呼ばれていましたが、Pythonの主要なHTTPクライアントやBun、Envoyにも影響すると分かり、10月23日ごろから今の呼び名が広がりました。Brandefenseのまとめによると、10月23日時点でCISAの悪用確認リストには載っていません。一方で、検証コードはすでに公開されています。

条件は「攻撃者が用意したBrotliデータを、自分の側で展開すること」です。AIエージェントのWeb取得、スクレイピング、Webhookの受信など、外部とデータをやり取りする自動化ほど、この条件に近づきます。

見る場所は4つ。そのうち2つは版表示を信じられない

場所 修正済みの目安 見落としやすい点
Claude Code 2.1.308以上 2.1.305〜2.1.307は中身が「Bun v1.4.4」でも未修正
n8n(Docker) 2.44.6以上、1.x系は1.123.87以上 2.44.5はNode 26.10.0のまま
Node.js 22.23.4/24.22.1/26.12.1以上 Brotliの版表示は修正後も1.1.0のまま。20系以前は修正版なし
Python brotli 1.2.1/brotlicffi 1.2.1.0以上 コードでimportしていなくても、requestsなどが勝手に使う

表の版は、各社の公開情報と、私が10月25日に公開パッケージを調べた結果を合わせたものです。以下、場所ごとに根拠を示します。

Claude Code:中身が「Bun v1.4.4」でも、2.1.307までは修正前

Claude Codeは、実行環境のBunを本体に同梱しています。公式のセットアップ手順によると、npmで入れた場合も同じネイティブバイナリが入り、実行時にNode.jsを使いません。つまり、Node.jsを更新してもClaude Codeは直りません。

Bunの告知では、影響を受けるのは1.4.3以前です。fetchがBrotliで圧縮された応答を自動で展開し、古いBunで作った実行ファイルは作り直さないと直らないとしています。Claude Codeの内部でどの処理がこの経路を通るかは公開されていません。それでも、外部のWebページやMCPサーバーと通信する道具ですから、私は真っ先に更新する対象だと考えています。

どの版から直ったのかは、Claude Codeの更新履歴に書かれていません。そこで、npmに公開されているmacOS用のパッケージを版ごとに取得し、中身を調べました。目印にしたのはBLOCK_SWITCHという文字列です。Brotliの修正コミットが新しく追加したエラーコードで、修正前のコードには存在しません。公式のBun 1.4.3では0件、1.4.4では3件見つかり、目印として使えることを確かめました。

  • 2.1.281(私の手元):Bun v1.4.3、目印0件
  • 2.1.305・2.1.306・2.1.307:Bun v1.4.4の表記、目印0件
  • 2.1.308・2.1.310:Bun v1.4.4の表記、目印3件

2.1.305〜2.1.307の「1.4.4」は、表記に添えられたコミット番号が公開のBunリポジトリで見つからず、正式版とは別のビルドのようです。「2.1.305以降なら修正済み」とする解説も見かけましたが、私の調べでは2.1.308が境目でした。

更新方法は入れ方で変わります。公式の自動更新を使っている場合は、claude updateですぐに更新できます。Homebrewで入れた場合は自動更新されないのでbrew upgrade claude-codeを、npmの場合はnpm install -g @anthropic-ai/claude-code@latestを実行します。HomebrewのClaude Codeは約1週間遅れのstableチャンネルですが、10月25日時点でnpmのstableは2.1.308になっていました。DISABLE_AUTOUPDATERで自動更新を止めている人は、手動で更新しない限り古いままです。更新後はclaude --versionで2.1.308以上になったかを確かめてください。

もう一つ、私の環境で見つかったものがあります。普段使っているclaudeとは別に、/usr/local/binに1.0.38という古いJavaScript版が残っていました。手元のNode.jsで動く旧形式で、本体の更新も止まっていたものです。PATHの順で普段は呼ばれませんが、which -a claudeで全部の場所を洗い出し、使わないものは消しておくのが確実です。

n8n:2.44.5は修正前のNode。1.x系も1.123.87で直った

n8nのDockerイメージは、イメージの中にNode.jsを持っています。n8nコミュニティのスレッドでは、n8nのサポート担当が10月22日に、stableの2.44.6はn8n本体とtask runnersの両方のイメージがNode 26.12.1で作られていると回答しています。

Docker Hubに公開されているイメージの設定を読んで、Node.jsの版を確かめました(x86_64版)。2.44.5はNode 26.10.0で修正前です。2.44.6と2.45.2、latest・stableタグは26.12.1でした。1.x系は1.123.86がNode 24.13.1、10月23日の1.123.87が24.22.1で、こちらも修正済みです。

n8nは、HTTP Requestノードで外部のURLを取得し、Webhookで外からの呼出しを受けます。先のスレッドでn8nのスタッフは、Brotliで圧縮されたリクエストを遮断するだけでは不十分だとして、Webhookの呼出し元を絞ることと、信頼できないコンテンツの処理をいったん止めることを勧めていました。すぐに更新できない場合の応急処置として参考になります。

動いているコンテナの中身はdocker exec コンテナ名 node -vで確認できます。私の環境ではDockerが動いていなかったため、このコマンドは実行していません。イメージの版は、上記のとおりレジストリの設定情報で確かめました。n8n Cloudの対応状況は確認できていません。

Python:brotliが入っているだけで、頼んでいない圧縮まで展開する

Pythonで問題になるのは、brotliとbrotlicffiという2つのパッケージです。GitHubの告知では、brotliは1.2.1、brotlicffiは1.2.1.0で修正されています。

やっかいなのは、自分のコードでimportしていなくても使われる点です。Aikidoの解説によると、requestsが内部で使うurllib3、httpx、aiohttpは、これらのパッケージが入っていれば自動でBrotliを展開します。しかも、送る側が「Brotliには対応していない」と伝えても、応答のヘッダーを見て展開してしまうとしています。

本当にそうなるのか、手元で試しました。Brotliで圧縮した無害な文字列を返すだけのサーバーを自分のPCで動かし、requestsで「gzipだけに対応している」と伝えて取得しました。条件はPython 3.12.9、requests 2.32.5、urllib3 2.6.3です。修正済みのbrotli 1.2.1を使っています。

import requests

r = requests.get("http://127.0.0.1:8765/", headers={"Accept-Encoding": "gzip"})
print(r.content[:20])

brotliがない環境では、圧縮されたままのバイト列が返りました。brotliを入れると、頼んでいないのにb'hello brotli'と展開されました。つまり、スクレイピングやRSS取得、Webhookの転送を書いた環境にbrotliが入っていれば、要求の内容に関係なく展開処理が動きます。

逆の見方もできます。私のMacにある3つのPython環境には、どれにもbrotliとbrotlicffiが入っていませんでした。入っていなければ、少なくともこの経路でrequestsやhttpxが展開することはありません。確認するときは、使っている環境ごとにpython3 -m pip show brotli brotlicffiを実行するか、後の確認コマンドで仮想環境をまとめて探します。見つかったらpip install -U "brotli>=1.2.1"で更新し、ロックファイルの指定も上げておきます。

Node.js:Brotliの版表示は、修正後も1.1.0のまま

Node.jsでは、node -p process.versions.brotliでBrotliの版を表示できます。これを見て「1.1.0だから未修正」と判断したくなりますが、それは誤りです。

Node.jsの公式のmacOS版バイナリを2つ取得して比べました。修正前の22.22.0も、修正後の22.23.4も、表示は同じ1.1.0です。Node.jsはBrotliの新版を取り込まず、修正部分だけを個別に取り込んだためです。先ほどの目印の文字列は、22.22.0で0件、22.23.4で3件でした。判断にはnode -vで表示されるNode.js自体の版を使ってください。

nvmなどで複数の版を入れている場合は、使っていない古い版も残っています。20系以前は2026年4月にサポートが終わり、修正版は出ません。私の手元にも20.11.0が残っていました。同じリリースではTLSのホスト名確認を回避できる欠陥も2件直っているので、HTTP2Shell以外の理由でも22系以降へ上げる価値があります。

macOS・Linuxで手元を確かめる確認コマンド

上の4か所を一度に見るコマンドです。読み取りだけで、何も変更しません。私のMacで実行して動作を確かめています。

which -a claude | while read -r c; do echo "$c: $("$c" --version 2>/dev/null)"; done
which -a node | while read -r n; do echo "$n: $("$n" -v)"; done
ls ~/.nvm/versions/node 2>/dev/null
find ~ -type d \( -iname 'brotli-*.dist-info' -o -iname 'brotlicffi-*.dist-info' \) 2>/dev/null
strings -n 8 "$(readlink -f "$(command -v claude)")" | grep -c BLOCK_SWITCH

1行目はClaude Codeのすべてのインストール先と版、2〜3行目はNode.jsの場所と版です。4行目はホームフォルダ以下の仮想環境にあるbrotliとbrotlicffiを探します。私の環境では約21秒かかり、何も見つかりませんでした。見つかった場合は、フォルダ名に入っている版を表の目安と比べます。

最後の行は、ふだん使うネイティブ版のClaude Codeに修正が入っているかを数えます。3なら修正済み、0なら未修正です。私の2.1.281では0でした。stringsはmacOSではXcodeのコマンドラインツールに含まれます。Windowsではclaude --versionとnode -vで版を見てください(Windowsでは試していません)。

どれから直すか:外とつながる常駐処理が先

私が優先するのは、外部からデータを受け取り続けるものです。公開しているn8nのWebhookや、常駐で外部のURLを取得し続けるスクレイピングのジョブは、攻撃者が用意したデータを受け取る回数がいちばん多くなります。次がClaude Codeです。自動更新を止めている人や、Homebrewで入れて更新していない人は、今日の時点でも古い版を使っている可能性があります。開発用PCに残った古いNode.jsとPythonの仮想環境は、その後でも間に合います。

すぐに更新できない場合の回避策もあります。Bunの告知では、fetchにdecompress: falseを渡すと展開しなくなるとしています。Pythonでは、brotliが不要な環境ならアンインストールすれば、先の実験どおりrequestsは展開しません。ただし、要求を無視してBrotliで返すサーバーからは、圧縮されたままの中身を受け取ることになります。あくまで修正版を入れるまでのつなぎです。

私の考えでは、今回の教訓は「版表示を一つ見て安心しない」ことです。Claude Codeの「Bun v1.4.4」もNode.jsの「brotli 1.1.0」も、それだけでは正しく判断できませんでした。各社の告知にある修正版の番号と、自分の手元の版を突き合わせるのが確実です。同じくAIが見つけたPHPの欠陥はphp2shellの確認手順で、Pythonのパッケージ改ざんへの備えはLiteLLM改ざん時の確認手順で扱っています。今日はまず、上の5行を実行してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次