# vm2: NodeVM builtin allowlist bypass via node:test.run() execArgv allows sandbox escape

vm2 NodeVM with node:test builtin allowed lets sandbox reach host node:test via doubled node: prefix and run() execArgv --eval for host RCE.

- Payout: Research
- Severity: critical
- Program: vm2
- Found by: the-vibe-dev
- Disclosed: 2026-10-01
- CVE: CVE-2026-92948
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-qhwx-74w5-xhxq
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-qhwx-74w5-xhxq
- Tags: area:oss domain:oss impact:internal-access impact:rce kind:research platform:ghsa sev:critical tech:nodejs technique:chained technique:source-review vuln:auth-bypass vuln:rce vuln:sandbox-escape

**Target:** NodeVM sandbox builtin loader (lib/builtin.js, lib/setup-node-sandbox.js)
**Root cause:** requireImpl strips one 'node:' prefix before builtin lookup, so 'node:node:test' normalizes to the stored 'node:test' key; the test family is absent from DANGEROUS_BUILTINS and the generic host-passthrough loader exposes host node:test, whose run() forwards attacker execArgv to a spawned unrestricted Node process.
**Steps:**
1. Configure NodeVM with `require: { builtin: ['node:test'], external: false }` on Node.js 24+
2. In sandbox call `require('node:node:test')` — prefix stripping maps it to stored key `node:test`
3. Call `run()` with `execArgv` containing `--eval=<JavaScript>`
4. Spawned host Node process executes the JavaScript outside vm2, importing host `fs` and writing marker
**How found:** Noticed Node.js 24 module.builtinModules exposes scheme-only 'node:test' entry, checked DANGEROUS_BUILTINS lacked 'test', then tested doubled 'node:' prefix normalization against the stored key and found run() execArgv passthrough.
**Exploitation:** Attacker with untrusted JS execution in the configured NodeVM requires the host node:test module via doubled prefix, then invokes run() with --eval payload; the child process runs with embedder's OS identity, filesystem, env and network access.
**Insight:** When a sandbox normalizes prefixes before allowlist lookup, try doubled prefixes ('node:node:x') to hit stored scheme-only keys; also audit any allowed builtin whose API spawns processes or accepts execArgv/--eval/--require.

