vm2 Sandbox Escape and Authorization Bypass
2026-09-27
Sandbox escape leading to arbitrary host code execution in vm2 (the npm sandbox library, CPE cpe:2.3:a:patriksimek:vm2) affects all versions before 3.12.2 when NodeVM is configured with a custom `require.external` resolver and `context: 'host'`. Because the resolver records the allowed module directory as an unanchored prefix pattern, untrusted guest code can require an allowlisted package (e.g. `foo`) and then require a non-allowlisted sibling sharing that prefix (e.g. `node_modules/foo2/index.js`), whose top-level code is loaded via `hostRequire` in the host process before `vm.readonly` wrapping, yielding code execution outside the sandbox. Exploitation requires the non-default host-passthrough external-resolver deployment plus a prefix-sharing sibling package, but needs no authentication or user interaction (CVSS:4.0 9.5, AT:P/PR:N/UI:N; assessed CVSS:3.1 AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H); no public exploit code was identified at time of analysis and the flaw is not in CISA KEV, though the vendor has published patched commits and version 3.12.2.
Denial of service in vm2 sandboxes before 3.12.2 allows an untrusted script running via VM.run to terminate the host Node.js process. The BaseHandler construct trap returns Reflect.construct's result without calling markHostPromiseHandled() the way the adjacent apply trap does, so if an embedder exposes a constructable host function whose constructor returns a resident rejected Promise, invoking it with `new` and discarding the result lets the rejection cross the sandbox bridge unhandled; under Node's default strict unhandled-rejection policy this is promoted to a process-terminating uncaught exception. The bug is unauthenticated in the sense that the attacker only needs to submit script code (PR:N/UI:N), but exploitation is conditional: it requires a specific embedder integration exposing such a constructable Promise-returning host constructor, which is the AT:P precondition and is not vm2 default behavior; no public exploit code was identified at time of analysis and the issue is not in CISA KEV.
Information disclosure and cross-boundary host memory corruption in vm2 before 3.12.2 let untrusted guest JavaScript read and modify bytes outside the sandbox whenever the embedding application explicitly allowlists Node's zlib builtin via require: { builtin: ['zlib'] }. vm2 fails to apply its Buffer backing-store ownership invariant (byteOffset === 0 && buffer.byteLength === length) to Buffers returned from host builtin modules, so zlib.deflateSync can hand back a pooled buffer whose .buffer getter exposes Node's entire 64 KiB shared small-buffer pool; a guest then builds a full-width view with Buffer.from(result.buffer, 0, result.buffer.byteLength) to disclose secrets (session tokens, decrypted material, DB rows) and corrupt unrelated host buffers sharing that pool. This is not reachable in a default vm2 deployment - it requires a non-default zlib allowlist, attacker-controlled script execution, and host secrets co-resident in the pool at exploitation time - and no public exploit code was identified at time of analysis; the vendor rates it CVSS 4.0 6.9 (Medium) with a vendor-released patch in 3.12.2.