# vm2 CLI provides no sandbox isolation - host-realm require() is reachable from sandboxed scripts

vm2 CLI runs scripts with require.external and no root, so require(__filename) re-executes in host realm, escaping the sandbox to full RCE.

- Payout: Research
- Severity: high
- Program: vm2
- Found by: oran-s
- Disclosed: 2026-10-01
- CVE: CVE-2026-92950
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jxxv-8r27-vm4p
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jxxv-8r27-vm4p
- Tags: area:oss domain:oss impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:source-review vuln:rce vuln:sandbox-escape

**Target:** vm2 CLI (bin/vm2, NodeVM.file)
**Root cause:** CLI invokes NodeVM.file with require:{external:true} but no root/context/builtin; resolver-compat's isPathAllowed returns true when rootPaths is undefined, and loadJS routes host-context paths through the real host require(), executing module bodies in the host realm before readonly() wrapping.
**Steps:**
1. Create `/tmp/poc.js` that tries `require('fs')`; on failure (sandbox realm) calls `require(__filename)`.
2. Run `node ./bin/vm2 /tmp/poc.js` (or `vm2 /tmp/poc.js`).
3. First pass: `require('fs')` throws 'Cannot find module fs' in sandbox.
4. `require(__filename)` resolves via resolver-compat loadJS with pathContext 'host', calling hostRequire on the file.
5. Module body re-executes in host realm; `fs.writeFileSync('/tmp/vm2.proof', ...)` succeeds.
**How found:** Code-read of the CLI entry (bin/vm2 → lib/cli.js) noting NodeVM.file options lacked root/context/builtin, then tracing resolver-compat defaults: rootPaths undefined makes isPathAllowed always true, and pathContext 'host' routes loadJS to hostRequire.
**Exploitation:** Attacker supplies a script file to the documented `vm2 <file>` CLI; the script's own require(__filename) causes host-realm re-execution, granting fs, child_process, process.dlopen, network and env access as the invoking user. No flags or interaction needed.
**Insight:** When a sandbox wrapper exposes a CLI, check whether the documented invocation sets the resolver's root/context options; an undefined rootPaths silently disables path gating, and any host-context load executes the module body before exports are proxied.

