概要
2026年10月に公開された CVE-2026-111497 は、Node.js に含まれる Brotli デコーダーで発生する範囲外書き込み (out-of-bounds write) の脆弱性である。Brotli は Google が開発した圧縮アルゴリズムであり、主に Web 経由で送受信するデータの圧縮や受信した圧縮データの展開に使用される。Web アプリケーションが Brotli で圧縮されたデータを受信すると、Brotli デコーダーがこれを展開する。しかし、攻撃者が不正に細工した圧縮データを送信した場合、脆弱な Brotli デコーダーはそれをエラーとして認識できず、データの処理を続行しようとする過程で脆弱性が発生する。攻撃者はこの脆弱性を悪用することで Node.js プロセスを終了させたりメモリ情報を漏えいさせたりできるほか、リモートコード実行を引き起こす可能性もある。
このように、サービス障害だけでなく、メモリ情報の漏えいやリモートコード実行につながる可能性があることから、Node.js プロジェクトは本脆弱性の深刻度を High と評価した。また、Google が登録した Brotli ライブラリの CVE レコードには CVSS v4.0に基づくスコアとして9.2が記載されており、Imperva Red Team は本脆弱性を 「Node2Shell」 と命名した。本ブログでは Brotli のブロック切り替え方式とデコーダーのエラー処理過程を分析し、脆弱なデコーダーが Node.js アプリケーションから呼び出される経路とその対策について解説する。
技術的背景
Brotli 圧縮技術
Web 上でデータを送受信する際には転送量を削減するため、元のデータを圧縮して送信することがある。Brotli は、その際に利用できる圧縮方式の1つである。利用できる状態にするには、データを受信した側で Brotli で圧縮されたデータを元の内容に展開する必要がある。この展開処理を担うのが Brotli デコーダーである。
デコーダーは圧縮データを読み取りながら元の内容を復元する。この際、データはブロックと呼ばれる単位で順番に処理される。圧縮データには、現在のブロックで処理するデータ量やその後に展開すべき内容に関する指示が含まれている。そのため、デコーダーは現在のブロックのデータをすべて処理し終えても、展開すべき内容が残っていれば次のブロックに移行して処理を続ける。
CVE-2026-111497
脆弱性の発生原因
問題は、攻撃者が整合性のない圧縮データをデコーダーに渡した場合に発生する。圧縮データに記載された指示によると、まだ展開すべき内容が残っている一方で、デコーダーが現在処理しているブロックで展開できるデータ量はすでに上限に達している。そのため、デコーダーは残りの内容を展開するために次のブロックへ移行しようとする。
しかし、実際に次のブロックへ移行しようとしても移行先のブロックに関する情報が存在しない。つまり、さらに展開する必要があると指示されているにもかかわらず、続けて処理するブロックが存在しない状態である。圧縮データの内容に整合性がないため、デコーダーはここでエラーと判断して処理を停止しなければならない。また、データを追加で受信しても解決する問題ではない。
ところが、脆弱なデコーダーは、このエラーを 「圧縮データがさらに届けば解決する」 と誤って解釈する場合がある。新たに受信したデータを小さな内部バッファーに格納して同じ処理を再試行するが、そもそもデータ不足が原因ではないため、いくら追加で受信しても次のブロックへ移行できない状態は変わらない。この処理が繰り返されると、最終的に内部バッファーの容量を超えてデータが書き込まれる可能性がある。これが範囲外書き込みである。
また、ブロックの切り替えに失敗したことを確認せず、圧縮データの展開処理を続行してしまう問題も存在した。ただし、前述した内部バッファーの容量超過は、エラーをデータ不足と誤認した場合に発生するものである。修正されたデコーダーでは、このようにブロックを切り替えられない状態と実際にデータが不足している状態を区別し、不正な圧縮データであると判断した場合は直ちに展開処理を中止する。
脆弱性によって発生する影響
範囲外書き込み (out-of-bounds write) の脆弱性とは、プログラムが定められた保存領域を超えて別のメモリ領域にデータを書き込んでしまう問題である。このように Node.js プロセスのメモリが破損すると、サービスが停止したりメモリ情報が漏えいしたりする可能性がある。また、条件によっては、攻撃者がサーバー上でコードを実行するリモートコード実行につながる可能性もある。
もちろん、細工された圧縮データを送信すれば、あらゆる環境で直ちにリモートコード実行が発生するわけではない。公開されている再現例では、特定の Node.js ビルドとアプリケーション構成においてコード実行が確認されており、修正版では同じ入力が拒否された。
攻撃の流れの分析
実際の攻撃はどのような順序で進むのだろうか。
攻撃者はまず、脆弱なバージョンの Node.js を使用しているサービスを探す。ただし、Node.js のバージョンが脆弱であるというだけで攻撃が成立するわけではない。そのサービスが外部から受信した Brotli 圧縮データを実際に展開する処理を備えており、攻撃者が細工したデータをその展開処理まで到達させられる必要がある。
攻撃者が細工した Brotli データを送り込める経路は、サービスの機能によって大きく3つに分類できる。
- クライアントが送信する HTTP POST リクエストの本文に含まれる場合우
- Node.js アプリケーションが外部サーバーから受信したレスポンスに含まれる場合
- Node.js アプリケーションが Brotli データやファイルを直接処理する場合
代表的な侵入経路は、クライアントからサーバーへ送信される HTTP リクエストである。リクエスト本文が Brotli 方式で圧縮されている場合、これに対応するアプリケーションは本文の内容を利用する前に圧縮データを展開する。そのため、攻撃者が細工した圧縮データをリクエスト本文に含めて送信すると、そのデータが Brotli デコーダーに渡される可能性がある。
Node.js アプリケーションが外部サーバーから受信したレスポンスを処理する過程でも細工された Brotli データが入り込む可能性がある。攻撃者が外部サーバーのレスポンスを制御したり、アプリケーションが攻撃者の指定したアドレスからデータを取得するよう誘導したりすれば、そのレスポンスに細工されたデータを含めることができる。
細工されたデータは、必ずしも Web リクエストを通じて直接送信される必要はない。アプリケーションが圧縮ファイルや別のシステムから受信したメッセージを直接展開する場合にも同様の問題が発生する可能性がある。ファイルは Web リクエストを通じてアップロードされることがあり、メッセージは別のシステムやメッセージキューを通じて配信されることがある。侵入経路にかかわらず、アプリケーションが該当データを実際に展開すると、脆弱な Brotli デコーダーに到達する。
脆弱なデコーダーが細工された圧縮データを処理すると、存在しない次のブロックへ移行しようとする不正な動作が発生する。デコーダーはこれをフォーマットエラーと判断して処理を中止せず、追加の入力データが必要な状態だと誤って判断する。その結果、定められた保存領域を超えてデータが書き込まれ、Node.js プロセスのメモリが破損する。
メモリが破損すると、サービスが停止したりメモリに保存されている情報が漏えいしたりする可能性がある。また、メモリ構造や実行環境などの複数の条件が満たされると、攻撃者が意図したコードをサーバー上で実行するリモートコード実行につながる可能性もある。以下の2本の動画は、脆弱な Node.js 環境において DoS 攻撃と RCE 攻撃を実際に再現した結果を示している。攻撃の成功に必要な条件は実行環境によって異なるため、実際の攻撃結果も状況に応じて変わる可能性がある。
[動画1] Node2Shell を利用した DoS の実証動画 (※韓国語)
[動画2] Node2Shell を利用した RCE の実証動画 (※韓国語)
対策
修正版へのアップデート
最も確実な対策は、サービスで実際に使用している Node.js を脆弱性が修正されたバージョン以降にアップデートすることである。Node.js プロジェクトが2026年10月21日に発表した各系列における最初の修正版は以下のとおりである。
| Node.js 系列 | 脆弱なバージョン | 修正版 |
|---|---|---|
| 22.x | 22.23.4 未満 | 22.23.4 以降 |
| 24.x | 24.22.1 未満 | 24.22.1 以降 |
| 26.x | 26.12.1 未満 | 26.12.1 以降 |
[表1] Node.js プロジェクトが発表した各系列の修正版
アップデートの際には、サーバーにインストールされている Node.js のバージョンを確認するだけでは不十分である。実際のサービスで使用する実行ファイルがコンテナイメージや配布ファイルに別途含まれている場合があるため、それらのファイルも置き換えたうえで関連するプロセスを再起動する必要がある。その後、稼働中のサービスに修正版が適用されていることを確認する。また、Node.js 以外の製品が Brotli ライブラリを個別に使用している場合は、その製品についてもパッチの適用状況を別途確認する必要がある。
修正版を適用できない場合
複数のサーバーを順番にアップデートする必要がある場合やサービスへの影響がないことを事前に確認しなければならない場合など、直ちに修正版へアップデートすることが難しいケースもある。製品に Node.js が組み込まれており、メーカーによるアップデートを待たなければならない場合もある。
このような場合は、まずサービスにおいて、外部から受信した Brotli データが展開される経路を確認し、アップデートが完了するまで該当する経路を一時的に制限する必要がある。
例えば、Web リクエストのうち、Brotli 圧縮データを処理する機能がある場合は、アップデートが完了するまで該当するリクエストを制限できる。プロキシや Web ファイアウォールを利用して Brotli 圧縮リクエストを遮断する方法もある。外部サーバーから Brotli で圧縮されたレスポンスを取得する機能については、許可されたサーバーからのみレスポンスを受信するよう制限したり、必要に応じて該当機能を一時的に停止したりすることができる。
こうした制限は攻撃の可能性を低減するための一時的な措置であり、正常な Web リクエストや外部連携機能にも影響を及ぼす可能性がある。そのため、サービスに必要な機能であるかを確認したうえで適用し、アップデートが完了するまでの間に限って維持することが適切である。
まとめ
Node2Shell は、一般的な圧縮データの処理過程においても、ランタイム内部のメモリに関する問題が攻撃に悪用される可能性があることを示している。アプリケーションが Brotli の展開機能を直接使用していなくても、Web リクエストの本文や外部サーバーから受信したレスポンスを処理する過程で Brotli デコーダーが呼び出される可能性がある。そのため、サーバーにインストールされている Node.js のバージョンや外部に公開されているアドレスを確認するだけでは実際の攻撃経路を見落とすおそれがあり、注意が必要である。
対策としては、現在稼働している Node.js プロセスが実際に使用している実行ファイルとバージョンを確認し、脆弱性が修正されたバージョンへ優先的にアップデートする必要がある。これと併せて、Web リクエスト本文、外部サーバーからのレスポンス、ファイル、メッセージキューなどを通じて受信する Brotli 圧縮データのうち、攻撃者が細工できるデータがサービス内部でどのように処理されるかを確認することも重要である。
直ちにアップデートすることが難しい環境では、不要な Brotli 展開機能を制限し、アップデート後には実際のサービスにおいて不正に細工された圧縮データが適切に拒否されることを確認する必要がある。
今回の事例は、アプリケーションに直接実装された機能だけでなく、フレームワークやランタイムが内部的に実行する処理も攻撃にさらされる可能性があることを示している。したがって、同様の脆弱性に対応する際には、使用しているコンポーネントのバージョンを確認するだけでなく、そのコンポーネントがサービスのどの機能から呼び出されているかまで把握する必要がある。
出展
- https://nodejs.org/en/blog/vulnerability/october-2026-security-releases
- https://nodejs.org/en/blog/release/v22.23.4
- https://nodejs.org/en/blog/release/v24.22.1
- https://nodejs.org/en/blog/release/v26.12.1
- https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/111xxx/CVE-2026-111497.json
- https://github.com/google/brotli/commit/0ed4268a4401abcb44720963
- https://github.com/nodejs/node/commit/49dff6f57a
- https://www.rfc-editor.org/rfc/rfc7932
- https://expressjs.com/en/guide/migrating-5/
- https://expressjs.com/en/resources/middleware/body-parser/
- https://www.imperva.com/blog/node2shell-from-brotli-data-to-remote-code-execution/
Categories: トレンド, 脆弱性, Uncategorized