[緊急警告] vm2のCritical脆弱性 (CVE-2026-47686) を解説 - サンドボックスエスケープでRCEの恐れ
はじめに:vm2とは?なぜフロントエンドエンジニアも注目すべきか?
vm2は、Node.jsアプリケーション内で信頼できないJavaScriptコードを安全に実行するためのサンドボックス環境を提供する人気のライブラリです。コードの分離、プラグイン実行、信頼できないスクリプトの評価など、セキュリティが求められる様々なシナリオで利用されています。
直接的にvm2を扱うのはバックエンドエンジニアやNode.js開発者が多いですが、フロントエンドエンジニアの皆さんも無関係ではありません。例えば、Node.jsベースのビルドツール、CI/CD環境、サーバーサイドレンダリング、あるいはデザインシステムでのコード実行環境など、Node.jsプロセスが内部的にvm2を利用しているケースは十分に考えられます。そのため、この脆弱性は広範囲なNode.jsエコシステム全体に影響を及ぼす可能性があります。
脆弱性の概要:Error.causeの盲点
今回報告された脆弱性 (ID: GHSA-m283-3h24-438v, CVE: CVE-2026-47686) は、vm2のバージョン 3.11.3 およびそれ以前に影響があります。CVSS 3.1 スコアは 9.9 Critical と評価されており、非常に深刻な問題です。
問題の根源は、JavaScriptのErrorオブジェクトにES2022で導入された`Error.cause`プロパティが、vm2のサンドボックスのエラーサニタイズ処理において適切に扱われていなかったことにあります。vm2はサンドボックス内で発生したエラーをホスト環境に渡す際に、悪意のあるオブジェクト参照が漏洩しないようにサニタイズ(無害化)する仕組みを持っています。しかし、`Error.cause`プロパティは、このサニタイズ処理から見落とされていました。
具体的には、もしホスト側(vm2を使用しているアプリケーション側)の関数が、`cause`プロパティに`process`のような強力なホストオブジェクトへの参照を持つエラーをスローした場合、サンドボックス内の悪意のあるコードはその`cause`プロパティを通じて`process`オブジェクトに直接アクセスできてしまいます。これにより、サンドボックスの保護を完全に回避し、ホスト環境で任意のコマンド実行 (RCE: Remote Code Execution) が可能になるのです。
根本原因の深掘り:`handleException`関数の盲点
この脆弱性の根本原因は、vm2の`lib/setup-sandbox.js`にある`handleException`関数にあります。この関数は、サンドボックス内でキャッチされたエラーをサニタイズする役割を担っています。
コードを見ると、`SuppressedError`や`AggregateError`といった特定のエラー型に対しては、その内部に含まれるエラー(`error`、`suppressed`、`errors[]`)を再帰的にサニタイズする処理が実装されています。しかし、それ以外の一般的なエラー型については、`handleException`関数は`e`を直接返すだけで、`Error.cause`プロパティの存在を完全に無視しています。
ES2022で`Error.cause`が導入されて以降、モダンなNode.jsアプリケーションではエラーチェーンの文脈でこのプロパティが頻繁に利用されています。ライブラリのラッパー、データベースアダプター、HTTPクライアントなどでエラーが発生した際に、元のエラーを`cause`として新しいエラーをスローすることは一般的なプラクティスとなっています。この「モダンな慣習」が、vm2の既存のサニタイズロジックの盲点を突く形となりました。
再現方法 (PoC):サンドボックスエスケープの実証
以下のPoCコードは、どのようにサンドボックスエスケープが達成されるかを示しています。ホスト側が`process`オブジェクトを`Error.cause`として持つエラーをスローする関数`hostFn`をサンドボックスに公開しています。
サンドボックス内のコードは`hostFn()`を呼び出してエラーをキャッチし、サニタイズされていない`e.cause`プロパティを通じてホストの`process`オブジェクトにアクセスします。そして、`process.mainModule.require('child_process').execSync('id').toString()`を実行することで、ホスト環境で任意のコマンド(この場合は`id`コマンド)を実行し、その結果を取得することに成功しています。
これは、サンドボックスのセキュリティ境界が完全に破られ、ホスト環境に対するフルアクセス権限が奪取されたことを意味します。悪意のあるアクターは、ファイルシステムへのアクセス、プロセスの生成、ネットワーク通信など、ホストのあらゆるリソースを操作できるようになります。
推奨される対策:直ちに対応を
この脆弱性に対する最も効果的な対策は、vm2を修正済みのバージョンにアップデートすることです。現状、影響を受けるのは`vm2 <= 3.11.3`なので、それ以降のバージョンがリリースされ次第、速やかにアップデートを適用してください。
もし直ちにバージョンアップが難しい場合でも、暫定的な回避策として、サンドボックスに公開するホスト側の関数で、`Error.cause`に`process`のような機密性の高いホストオブジェクトへの参照を含めないように、エラーハンドリングを厳密に見直すことが推奨されます。ただし、これは根本的な解決策ではないため、あくまで一時的な対応と考えるべきです。
提案されている修正は、`handleException`関数の先頭で、全ての種類のエラーに対して`Error.cause`プロパティが存在する場合は、それを再帰的にサニタイズするというものです。これにより、`cause`プロパティが見落とされることなく、適切に無害化されるようになります。
まとめ
vm2のサンドボックスエスケープ脆弱性は、その深刻度から見ても非常に注意すべき問題です。たとえ直接vm2を利用していなくても、依存関係のツリーにvm2が含まれている可能性を考慮し、ご利用のプロジェクトの依存関係をチェックすることを強く推奨します。
Node.jsエコシステム全体におけるセキュリティリスクを最小限に抑えるためにも、最新のセキュリティ情報を常にチェックし、適切なパッチがリリースされ次第、速やかに適用するセキュリティベストプラクティスを心がけましょう。