不正な形式の圧縮ストリーム、無視されたエラー、そしてバッファ末尾を越える書き込み。2026年10月21日、Node.jsは同梱するBrotliデコーダーの境界外書き込みを修正したバージョン22.23.4、24.22.1、26.12.1を公開しました。その翌日の10月22日には、Impervaが報告したとおり、Linux arm64向けの公式Node.js 24.22.0 Dockerイメージ上でコード実行に成功した例が出ています。この脆弱性は現在CVE-2026-111497として追跡されており、CVSS v4.0の基本スコアは9.2(Critical)です。広く「Node2Shell」と呼ばれています。
10月23日時点で、実環境での悪用は確認されておらず、Node2ShellはCISAのKnown Exploited Vulnerabilities(KEV)カタログにも追加されていません。しかし、公開された概念実証(PoC)コードはすでに検証されており、パッチ公開からPoC登場までの間隔は約1日でした。セキュリティチームは、管理下にないBrotliデータをNode.jsサービスがデコードしている箇所をすべて洗い出し、まずそこからパッチを適用する必要があります。
Sysdig脅威リサーチチーム(TRT)は、Node2Shellに関する公開リサーチを分析しました。対象は、影響を受けるのは誰か、何が実証され何が主張にとどまるのか、ランタイムの可視化で何を検知できるのか、パッチ適用までに何ができるのか、といった点で、防御側の理解を助けることを目的としています。
タイムライン
|
日付 |
出来事 |
|
2026年10月14日 |
Node.jsがリリースを事前告知し、影響を受けるバージョンラインと、最大の深刻度が「高」であることを明示 |
|
2026年10月21日 10:38 UTC |
Node.jsがv22.23.4、v24.22.1、v26.12.1を公開 |
|
2026年10月21日 15:47 UTC |
修正公開の約5時間後に、このCVEに関する最初の公開GitHubリポジトリが出現 |
|
2026年10月21日 19:27 UTC頃 |
Brotliプロジェクトが1.0.10、1.1.1、1.2.1を公開(いずれもCVE-2026-111497を記載) |
|
2026年10月22日 |
GoogleのCVEレコードが公開され、CVSS v4.0で9.2のスコアを付与 |
|
2026年10月22日 |
ImpervaがNode.js 24.22.0でのコード実行を示すリサーチを公開 |
影響を受けるNode.jsのバージョン
バグの所在はNode.jsのコードではなくBrotliです。ただしNode.jsは独自のコピーを同梱しているため、修正にはランタイム自体の更新が必要です。
Node.jsのアドバイザリは、この脆弱性の深刻度を「高」と評価しています。一方、GoogleはCVSS v4.0で9.2の「Critical」と評価しています。ただし実際の深刻度は、自社のコードがデコーダーに到達するかどうかという露出の度合いによって変わります。
|
Node.jsバージョン |
サポート終了日 |
修正バージョン |
|
26.x |
2029年4月30日 |
26.12.1 |
|
24.x |
2028年4月30日 |
24.22.1 |
|
22.x |
2027年4月30日 |
22.23.4 |
|
25.x |
2026年6月1日(終了済み) |
修正なし |
|
20.x |
2026年4月30日(終了済み) |
修正なし |
Node.jsは、サポート終了(EOL)バージョンはセキュリティリリースの影響を常に受けるとしています。Node.js 25や20、それ以前を運用している組織は、これらのホストを脆弱なものとして扱うべきです。今後パッチが提供されることはありません。
ディストリビューションのパッケージは別途確認が必要です。10月23日に確認したDebianのトラッカーは、bookwormのnodejs 18.20.4、trixieの20.19.2、forkyの24.21.0、sidの24.22.0を脆弱として挙げています。また、DebianのnodejsはシステムのBrotliライブラリを使用すると記しています。この場合、修正はランタイムだけでなくライブラリ側に適用されます。
DebianのBrotliパッケージも、トラッカーに記載されたすべてのリリースで脆弱です。どのリリースにも修正バージョンは示されていません。開発ブランチのunstableでも、brotliとnodejsの両方が未修正と表示されています。10月23日時点で、どちらのコンポーネントにもパッチ適用済みのDebianパッケージはありません。Debianはnodejsのエントリの緊急度を「unimportant」としており、Node.jsの「高」という評価とは異なります。ただし、トラッカーはその理由を説明していません。
CVEレコードは、根本原因のバグがGoogleのBrotliライブラリ1.0.3から1.2.0に存在し、1.0.10、1.1.1、1.2.1で修正されたとしています。この範囲のBrotliビルドを同梱するその他のソフトウェアも、さらなる分析やベンダーへの問い合わせを行う価値があります。
影響はDebianに限りません。Ubuntu、Fedora、RHEL、Alpineのパッケージも、同梱コピーではなくシステムのBrotliライブラリを使っている可能性があります。その場合、修正はディストリビューションのBrotliパッケージ経由で届くため、Node.jsのバージョン番号だけでは特定のインスタンスにパッチが適用済みかどうかを判断できません。
Aikidoによると、Bunも影響を受けます。1.4.3以前のすべてのバージョンが脆弱で、Bun 1.4.4に修正が含まれています。
Node2Shellのバグ(CVE-2026-111497)の仕組み
Brotliは圧縮フォーマットで、Node.jsはzlibモジュールのネイティブデコーダーを通じてこれをサポートしています。CVEレコードはc/dec/decode.cのバッファオーバーフローと説明し、2種類の脆弱性タイプを挙げています。境界外書き込み(CWE-787)と、戻り値の未検査(CWE-252)です。
後者が仕組みを説明しています。細工されたストリームは、データブロックの種類を1つだけ宣言したうえで、デコーダーにブロックタイプの切り替えを求めます。正しいデコーダーであれば、ここでエラーを出して停止します。しかしパッチ未適用のデコーダーはエラーを無視して処理を続け、バッファの末尾を越えて書き込みます。Semgrepは、根本的な欠陥を、デコーダーが不完全な入力と不正な入力を混同し、不正な形式のストリームを処理し続けることだと説明しています。
修正は小規模です。Node.jsは、ストリームがブロックタイプを1つしか宣言していない状態でブロック切り替えが起きた場合に、デコーダーが即座に失敗するようにするアップストリームのBrotliコミット(0ed4268a)をチェリーピックしました。あわせて、新しいエラー定数BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCHも追加しています。
到達可能なのはどこか
Node.jsが単独でBrotliをデコードすることはありません。アプリケーションが影響を受けるのは、自身のコードか、利用しているライブラリが、攻撃者の制御するBrotliデータを展開する場合です。Semgrepは、いくつかの入り口を確認しています。
|
経路 |
デコーダーに到達するか |
詳細 |
|
express.json()を使うExpress 5 |
到達する(デフォルト) |
Express 5.3.0はbody-parser ^2.3.0に依存しています。body-parser 2.xはbrボディをデコードし、inflateオプションはデフォルトでtrueです。素のNode.js HTTPサーバーは、受信したBrotliボディを自動ではデコードしません。 |
|
express.json()を使うExpress 4 |
body-parser経由では到達しない |
body-parser 1.20.xはdeflateとgzipのみを処理し、その他のエンコーディングには415を返します。 |
|
サーバーサイドのfetch() |
到達する(攻撃者が影響を及ぼせるレスポンスの場合) |
Node.jsのfetchは、Content-Encodingヘッダーにbrが含まれていれば、常にBrotliデコーダーでレスポンスを展開します。Accept-Encoding: identityを送っても防げません。ユーザーが指定したURLを呼び出す機能(Webhookなど)は、典型的な標的になります。 |
|
node:zlibの直接利用 |
到達する |
createBrotliDecompress()は、攻撃者が制御するデータを受け取る場合に露出します。 |
|
Koa(co-body経由) |
到達する |
Brotliのリクエストボディはco-bodyを通って展開処理に渡されます。Semgrepは、@koa/bodyparser、koa-body、Egg、Strapiも挙げています。 |
|
@fastify/compressを使うFastify |
到達する |
このプラグインを登録すると、Fastifyのcontent-typeパーサーが動く前にリクエストの展開処理が追加されます。 |
優先すべきは受信経路です。body-parserをグローバルにマウントしている場合、content-encodingとパーサーの条件次第で、ボディを受け付ける多くの公開ルートに到達し得ます。ただし、送信経路も重要です。組織のサービスが攻撃者の制御するサーバーからデータを取得すると、そのレスポンスによってサービスが攻撃される恐れがあります。
Express 4が安全というわけではありません。この評価はbody-parserだけを対象にしたものです。他のミドルウェアやフレームワーク、リバースプロキシ、組織独自のコードがBrotliをデコードしている可能性は残ります。
Node2Shellの悪用:実証されたことと主張にとどまること
Impervaは、Linux arm64上の公式Node.js 24.22.0イメージに対するコード実行を実証しました。ただし、実行には複数回の試行が必要だったとしています。デバッガーや改変バイナリのない、起動直後のコンテナでは、テストはマーカーファイルの作成で終わりました。パッチ適用済みの24.22.1は、同じ入力をフォーマットエラーとして拒否しました。Impervaはエクスプロイトコードを公開していません。
公開PoCについては、10月22日20:28 UTCの時点でGitHub検索に11件のリポジトリがヒットしました。あるラボは、Node.js 20.19.5、22.23.3、24.22.0、26.12.0でクラッシュを確認し、修正版の22.23.4、24.22.1、26.12.1は同じ入力を拒否すると報告しています。別のチームは3回中3回でローカルのコマンド実行に成功したと報告しましたが、パッチ未適用のシステムBrotliライブラリを読み込むビルドと、予測可能なメモリレイアウトが必要でした。このチームは、アドレスのランダム化が有効な状態でのブラインドなリモート実行は成功しなかったとしています。
一方で、根拠が薄い部分もあります。あるリサーチは、問題の書き込みに到達できるBrotliストリームは存在せず、実際の影響はサービス拒否(DoS)だと主張しています。修正コミットの入力を使った独立テストでは、Node.js 24.22.0で修正前のビルドでもパッチ適用済みのビルドでもエラーになりました。そのため、このテストだけでは書き込みが起きることを示せません。Konfirmityは、修正コミット自体がこのバグを低深刻度で悪用が容易ではないと説明していると指摘しています。
信頼できるリモートコード実行(RCE)が再現されたのは、これまでのところ1つの環境だけです。これに対し、クラッシュは研究者にとって容易に再現できています。組織は、どこでもクラッシュが起こり得る結果だと想定すべきです。攻撃者が制御し得るBrotliをサービスがデコードする環境では、シェル奪取も現実的なリスクとして扱う必要があります。
Node2Shellの影響
公開時点で、ワームや大規模な悪用キャンペーン、プラットフォームを問わず確実に動作するエクスプロイトを示す情報は公表されていません。ただし、研究者は次の影響を実証しています。
- サービス拒否:公開PoCの作者は、前述のリポジトリに基づき、パッチ未適用のNode.jsでプロセスがクラッシュすると報告しています。攻撃者は、ユーザーから受け取ったBrotliをデコードするあらゆるサービスを停止させられます。
- Node.jsプロセス権限でのコード実行:Impervaは、1つのイメージとアーキテクチャで、複数回の試行を経てこれを実証しました。攻撃者のコードはNode.jsプロセスの権限で動作し、データを盗み出す恐れがあります。
- メモリ漏えい:Vercelによると、研究者はパッチ未適用の22.x、24.x、26.xで、Node.jsプロセス内のメモリ漏えいとコマンド実行を実証しました。コード実行に失敗しても、漏えいしたメモリから認証情報などのデータが露出する恐れがあります。
Node2Shellの検知方法
マネージドポリシーを利用しているSysdig Secureのユーザーは、Node2Shellを特定し対応するための検知機能をすでに利用できます。Threat Intelligenceのエントリで露出箇所を把握でき、ランタイムルールで悪用とその後の攻撃者の動きを捕捉できます。
脅威インテリジェンス
Sysdig Threat Intelligenceフィードは、Node2Shellのエントリを公開しました。修正版の26.12.1、24.22.1、22.23.4より古いNode.jsバージョン、またはEOLラインを実行しているホストとワークロードを一覧にします。ホストまたはワークロードの件数を選択すると、影響を受けるアセットを絞り込んだ検索が開きます。
ランタイム検知
悪用がきれいに成功することはまれです。失敗した試行ではNode.jsプロセスがクラッシュし、Impervaの実証でも複数回の試行が必要でした。Sysdig Runtime Behavioral Analyticsポリシーに追加された新しいマネージドルールNode.js Process Crash Followed by In-Place Program Executionは、Node.jsのクラッシュと、同じワークロードでその後に起きる不審なプログラム実行を関連付けます。これはNode2Shellの攻撃チェーンに見られるパターンです。
エクスプロイトが成功すると、攻撃者はNode.jsのサービスユーザーとしてコマンドを実行できます。よくある次の手口は、対話型シェルの起動、マルウェアのダウンロード、暗号資産マイニング、コンテナからのシークレットやクラウドトークンの窃取です。Sysdig Secureがデフォルトで有効にしているマネージドポリシーは、この種の活動をすでにアラートとして検知します。エクスプロイト自体が見えなくても、ユーザーは保護を受けられます。
Node2Shellの緩和策
パッチ適用
- Node.jsを22.23.4、24.22.1、26.12.1のいずれかに更新する。Impervaは、デコーダーを修正できるのはNode.jsの更新だけだとしています。
- Bunは、稼働している場所すべてで1.4.4以降にアップグレードする。
- コンテナイメージは、パッチ適用済みのベースイメージから再ビルドし、稼働中のコンテナでnode –versionを実行して確認する。node:24のような可変タグは、キャッシュ済みイメージから再ビルドすると古いバージョンのままになるため、先にdocker pullを実行する。Dockerfileの固定バージョンは24.22.1以降にする。
- パッケージマネージャーは、思い込まずに確認する。Homebrewは、リリースの約10時間後もnode 26.12.0、node@24 24.22.0、node@22 22.23.3を配布していました。
- Node.js 20以前は22.xまたは24.xに置き換える。これらに修正は提供されません。
パッチ適用までに到達可能性を下げる
- 可能な範囲でリクエストの展開処理を無効化する。body-parserでは、
express.json({ inflate: false })とすると、圧縮されたボディが415で拒否される。事前にクライアントをテストすること。この設定ではgzipも拒否される。 - クライアントがbrを送信しない環境では、プロキシまたはロードバランサーでリクエストボディの
Content-Encoding: brを拒否する。Brandefenseが提案しているが、ベンダーのガイダンスではなく同社独自の提案である。頼る前にテストすること。サービスが取得するレスポンスは対象外である。 - 管理下にないサーバーへのfetch呼び出しと、
createBrotliDecompress()の直接利用を監査する。 - WAFがあれば追加の防御層として重ねる。ImpervaはWAFルールを追加したとし、影響を受けるパスで信頼できないBrotliトラフィックを制限するよう勧めている。あくまで防御層の一つであり、修正の代わりにはならない。
被害範囲の限定
- Node.jsサービスは非特権ユーザーで実行し、可能な限りシークレットをプロセス環境に置かない。コード実行はNode.jsプロセスの権限で行われる。
- Webに公開されたNode.jsプロセスで、シェルの起動や予期しない外向き接続がないか監視する。
環境全体での対応
- コンテナ、CIランナー、サーバーレス関数、ビルドサーバー、独自のNode.jsを同梱するツールなど、すべてのNode.jsランタイムを棚卸しする。
まとめ
Node2Shellは、すべてのNode.jsサービスに存在するバグではありません。攻撃者が影響を及ぼせるBrotliをデコードするサービスに存在するバグです。デフォルトのJSONパースを使うExpress 5は、そうしたインスタンスを数多く生み出しています。これまでに実証された影響は、大規模なクラッシュと、限定的な構成でのコード実行です。したがって、パッチの適用順は到達可能性に従うべきです。
ただし、本当の警告はタイムラインにあります。Node2Shellでは、修正の公開から5時間後にCVEを追跡する公開リポジトリが現れ、1日以内に動作するPoCが公開されました。この欠陥は、Node.jsやその他のソフトウェアが同梱するネイティブライブラリにあるため、それぞれが個別に修正を提供しなければなりません。セキュリティチームは、ランタイムの下層にあるネイティブライブラリで、こうした脆弱性がますます短い時間軸で発見されることも想定しておく必要があります。
セキュリティチームが今週取り組むべきは、まず棚卸し、次に到達可能性の高い順のパッチ適用、そしてパッチ未適用のものに対する最小権限の徹底です。ランタイムセンサーはオーバーフローそのものを検知しませんが、エクスプロイトが成功した後の挙動は捕捉します。だからこそ、侵入後の振る舞いは注目に値する最後の砦なのです。
翻訳元: https://webflow.sysdig.com/blog/node2shell-cve-2026-111497-detecting-the-node-js-brotli-rce
