GitHub Advisoryadvisory · npm
GHSA-8hr7-r645-pc6w vm2: NodeVM nesting guard accepts array-shaped require and permits host RCE
CRITICAL
Official page ↗
- Aliases
- CVE-2026-92935
- Ecosystem
- npm
- Packages
- vm2
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H
- Weaknesses
- CWE-913
- Reviewed
- 2026-10-01
Affected packages
• npm vm2: >= 3.11.4, < 3.11.7 → fixed in 3.11.7
Description
Summary
The `NodeVM` constructor computes `hasRealRequireConfig` using `typeof requireOpts === 'object' && requireOpts !== null`, so `require: []` bypasses the guard intended to reject `nesting` without an explicit require configuration. `makeResolverFromLegacyOptions()` then destructures the array to undefined option fields and returns a resolver containing only `NESTING_OVERRIDE.vm2`. Any attacker whose JavaScript is executed by a downstream `NodeVM` configured with `{nesting: true, require: []}` can load the host `vm2` module, create an inner `NodeVM` with an attacker-selected builtin allowlist, and execute commands as the host process. No equivalent plain-object validation exists in `makeResolverFromLegacyOptions()`.
Array is converted into the vm2-only resolver:
https://github.com/patriksimek/vm2/blob/54b54b74a382577f0bcd0538c5bf99acdcd7f53b/lib/resolver-compat.js#L205-L226
Nesting loader returns the host VM constructors:
https://github.com/patriksimek/vm2/blob/54b54b74a382577f0bcd0538c5bf99acdcd7f53b/lib/nodevm.js#L640-L645
Proof of Concept
Preconditions:
• The host creates `NodeVM` with truthy `nesting` and array-shaped `require`.
• The attacker can supply JavaScript executed by that `NodeVM`.
```javascript
'use strict';
const {NodeVM} = require('./index.js');
const outer = new NodeVM({nesting: true, require: []});
const result = outer.run(`
const {NodeVM} = require('vm2');
const inner = new NodeVM({require: {builtin: ['child_process']}});
module.exports = inner.run(
"module.exports = require('child_process').execSync('id').toString()"
);
`);
console.log(result);
```
```text
uid=1000(lohar) gid=1000(lohar) groups=1000(lohar)
```
The `hasRealRequireConfig` guard fails open because it returns `true` for arrays, although arrays are not `VMRequire` configuration objects. `makeResolverFromLegacyOptions()` applies object destructuring to the array, obtains undefined `builtin` and `external` values, merges `NESTING_OVERRIDE`, and returns before any external-module control is relevant. Outer builtin restrictions do not constrain the attacker-created inner `NodeVM`, whose `require` configuration is selected inside the sandbox.
Failed shape check:
https://github.com/patriksimek/vm2/blob/54b54b74a382577f0bcd0538c5bf99acdcd7f53b/lib/nodevm.js#L304-L307
Impact
An attacker can execute arbitrary commands with the host Node.js process privileges, including reading secrets, modifying files, and accessing the host network. GHSA-m4wx-m65x-ghrr covers the same nesting primitive but does not cover array-shaped `require` values and incorrectly identifies 3.11.4 as patched.
> Exploitation is limited to downstream applications that enable `nesting` and pass the malformed array configuration.
Related
Alias · CVE (1)
- CVE-2026-92935 vm2 is a sandbox for running untrusted Node.js code. vulnerability
Weakness · CWE (1)
- CWE-913 Improper Control of Dynamically-Managed Code Resources weakness
References
- https://github.com/patriksimek/vm2/security/advisories/GHSA-8hr7-r645-pc6w web
- https://nvd.nist.gov/vuln/detail/CVE-2026-92935 advisory
- https://github.com/patriksimek/vm2/commit/05894eca1dc6a2b1a986f312c88255288a983d22 web
- https://github.com/patriksimek/vm2/commit/54b54b74a382577f0bcd0538c5bf99acdcd7f53b web
- https://github.com/patriksimek/vm2 package
- https://github.com/patriksimek/vm2/releases/tag/v3.11.7 web
- https://www.vulncheck.com/advisories/vm2-nodevm-remote-code-execution-via-array-shaped-require web