JavaScriptサンドボックス完全比較2026:untrustedコードを安全に実行する6つの選択肢

元記事を読む
キュレーターコメント

untrustedコードの実行環境選びは「なんとなく動く」では済まないセキュリティ課題。vm2が静かに死んだ今、isolated-vmへの移行を検討しているNode.jsエンジニアに刺さる内容です。

概要

信頼できないJavaScriptコードをサーバーで実行したい——プラグインシステム、コードエディタのプレビュー機能、ユーザー定義スクリプトの実行環境など、そのニーズは思いのほか多い。しかし、適切なサンドボックスを選ばなければセキュリティホールに直結する。今回、Simon WillisonがClaude Codeを使ってこのテーマを深掘りした調査結果が公開された。

なぜJavaScriptサンドボックスは難しいのか

Node.jsはデフォルトでシステムリソースへのフルアクセスを前提に設計されている。require('fs')child_processを呼ばれたら終わり——そのリスクを封じるのが「サンドボックス」だ。しかし、JavaScriptのプロトタイプチェーンやグローバルスコープの特性から、完全な隔離は技術的に非常に難しい。vm2の廃止(メンテナがセキュリティ上の理由でプロジェクトを放棄)はその象徴的な出来事だった。

6つのアプローチ徹底比較

調査では以下のオプションが評価された:

  • Node.js組み込み

    • worker_threads:別スレッドで実行するが、デフォルトでは隔離不十分
    • node:vm:コンテキスト分離はできるが、プロトタイプ汚染でエスケープ可能
    • Permission Model(Node.js 20+):--allow-fs等でファイルアクセスを制限できる新機能
  • npmパッケージ

    • isolated-vm:V8のIsolateを直接使い、メモリ・CPUを厳格に制御。現状最も信頼性が高い
    • vm2:過去の定番だがセキュリティ上の理由でメンテナンス終了。新規採用は非推奨
  • 代替エンジン

    • quickjs-emscripten / QuickJS-NG:QuickJSをWasm化してNode上で動かす。V8より遅いが完全な隔離を実現
    • ShadowRealm:TC39提案。ブラウザ・Node両対応を目指すが、現時点では制限多め
    • Deno Workers:Deno自体を使う場合の選択肢。パーミッションモデルが洗練されている

実装の第一歩:isolated-vmのコード例

import ivm from 'isolated-vm';

const isolate = new ivm.Isolate({ memoryLimit: 128 }); // 128MB制限
const context = await isolate.createContext();

// グローバルにlogを注入
await context.global.set('log', new ivm.Reference((...args) => console.log(...args)));

const script = await isolate.compileScript('log.applyIgnored(undefined, ["hello from sandbox"])');
await script.run(context);

CPU時間制限やメモリ制限をコンストラクタで指定できる点がisolated-vmの強みだ。

まとめ・選び方ガイド

用途別のおすすめはこうなる:

  • 本番・高セキュリティ要件isolated-vm一択(V8 Isolate + メモリ制限)
  • 完全隔離・パフォーマンス不問quickjs-emscripten(Wasm隔離)
  • Node.js 20+の制御で十分 → Permission Model + worker_threadsの組み合わせ
  • vm2は今すぐ移行 → 代替はisolated-vmquickjs-emscripten

Simon WillisonがClaude Codeに調査を依頼し、当初の質問(worker_threadsのサンドボックス活用)を大幅に超えた比較レポートが生成されたというプロセスも興味深い。AIをリサーチツールとして使う実例としても参考になる。元記事のリンク先には調査レポート全文が掲載されているので、実装を検討している方はぜひ読んでほしい。