# NodeVM builtin denylist bypass via process and inspector/promises allows host code execution

vm2 NodeVM's builtin denylist omits process and inspector/promises, letting sandboxed code reach child_process and Runtime.evaluate to run code in the host process.

- Payout: Research
- Severity: critical
- Program: vm2
- Found by: spbavarva, VladimirEliTokarev
- Disclosed: 2026-05-29
- CVE: CVE-2026-47140
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-rp36-8xq3-r6c4
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-rp36-8xq3-r6c4
- Tags: area:oss domain:oss impact:internal-access impact:rce kind:research platform:ghsa sev:critical tech:nodejs technique:incomplete-fix technique:source-review vuln:rce vuln:sandbox-escape

**Target:** NodeVM sandbox builtin require allowlist (lib/builtin.js)
**Root cause:** The dangerous-builtin denylist in lib/builtin.js lists module, worker_threads, cluster, vm, repl and inspector but omits `process` and `inspector/promises`; non-denied builtins are exposed to the sandbox via `vm.readonly(hostRequire(key))`, so these modules leak host-side execution primitives.
**Steps:**
1. Configure NodeVM with require.builtin allowing `process`, `inspector/promises`, or `*`.
2. Confirm restrictions: `require("inspector")` and `require("child_process")` are BLOCKED.
3. Bypass 1: `require("process").getBuiltinModule("child_process").execFileSync(...)` spawns a host child process.
4. Bypass 2: `require("inspector/promises").Session().post("Runtime.evaluate", ...)` evaluates JavaScript in the host process.
5. Run `node poc/dangerous-builtin-denylist-rce.js` from the vm2 repo root (vm2 3.11.2, Node v25.9.0).
**How found:** Reviewed the builtin denylist in lib/builtin.js and noticed it enumerated dangerous modules by exact name but missed `process` and the `inspector/promises` subpath; then checked how non-denied builtins are exposed (readonly hostRequire) and tested whether those two modules reach host execution primitives.
**Exploitation:** Attacker supplies untrusted JS executed inside NodeVM where require.builtin permits process, inspector/promises or wildcard; sandboxed code calls process.getBuiltinModule('child_process') to spawn host processes or opens an inspector session and posts Runtime.evaluate to run arbitrary JS in the host, yielding file read/write, process spawn and host env secret access.
**Insight:** Denylists of exact module names miss subpath exports (inspector/promises) and meta-modules like process that can re-import blocked builtins via getBuiltinModule; enumerate Node's full builtin namespace and block by prefix family rather than exact names.

