Loading...
Skip to main content

CVE-2026-92948 — Vulnerability in vm2 — CVE Details

CRITICAL

vm2: NodeVM builtin allowlist bypass via node:test.run() execArgv allows sandbox escape

Published October 1, 2026Updated October 1, 2026Source: osv

Summary

## Summary On Node.js 24 and newer, `vm2` can expose the host `node:test` module to sandboxed `NodeVM` code when the embedder explicitly allows the `node:test` builtin. Sandbox code can reach that module through `require('node:node:test')` and call `run()` with attacker-controlled `execArgv`. `node:test.run()` starts a separate Node process for process-isolated test execution and forwards the supplied `execArgv` values to that process. Supplying `--eval=<JavaScript>` therefore executes arbitrary JavaScript in an unrestricted host Node process, outside the `NodeVM` sandbox. The PoC confirms that direct sandbox imports of `fs`, `child_process`, `module`, and `process` remain denied before the spawned process imports host `fs` and writes a harmless marker. ## Affected versions and environment - Package: `vm2` - Affected versions: `>=3.9.6, <=3.11.5` - Latest reproduced version: `3.11.5` - Reproduced runtime: Node.js `v24.18.0` - Exact path is not present on Node.js 22 because `module.builtinModules` does not expose the scheme-only `node:test` entry there - Configuration prerequisite: ```js require: { builtin: ['node:test'], external: false } ``` The lower version boundary was tested directly: `vm2@3.9.5` blocks `require('node:node:test')`, while `vm2@3.9.6` permits the exploit path. Representative releases through `3.11.5` were also reproduced. ## Root cause The issue is a combination of builtin admission, generic host passthrough, and prefix normalization: 1. On Node.js 24+, `module.builtinModules` includes the scheme-only key `node:test`. 2. `lib/builtin.js` builds `BUILTIN_MODULES` from that array. The family-based `DANGEROUS_BUILTINS` protection does not include `test`, so `node:test` remains eligible. 3. When the embedder explicitly allows `node:test`, `addDefaultBuiltin()` stores it through the generic loader: ```js builtins.set(key, special ? special : vm => vm.readonly(hostRequire(key))); ``` 4. In `lib/setup-node-sandbox.js`, `requireImpl()` strips one `node:` prefix before builtin lookup: ```js if (localStringPrototypeStartsWith(filename, 'node:')) { id = localStringPrototypeSlice(filename, 5); nmod = loadBuiltinModule(id); } ``` 5. Consequently, sandbox code requesting `node:node:test` is normalized to the stored key `node:test` and receives a readonly proxy to the host module. 6. The readonly proxy does not make `node:test.run()` safe. Calls are forwarded to the host implementation, which accepts attacker-controlled `execArgv` for a newly spawned Node process. 7. `--eval=<attacker JavaScript>` runs outside vm2 and has normal host builtin access. The doubled prefix is the reachability mechanism, but the security boundary failure is broader: the generic host-passthrough loader treats the `test` builtin family as safe even though its `run()` API can launch unrestricted Node processes. ## Proof of concept From the `poc` directory: ```bash npm ci --ignore-scripts --no-audit --no-fund node repro.js ``` Expected successful result on Node.js 24+ includes: ```json { "vm2Version": "3.11.5", "nodeVersion": "v24.18.0", "markerExists": true, "childIsDistinctProcess": true, "marker": { "hostCodeExecution": true } } ``` The PoC writes only `host-rce-marker.json` in its own directory and does not invoke a shell, contact a network service, or access third-party data. ## Impact An attacker who is intentionally permitted to execute untrusted JavaScript in the affected `NodeVM` configuration can escape the sandbox and execute arbitrary JavaScript under the embedder's operating-system identity. This provides the spawned process with the host user's filesystem, environment, network, and process-execution permissions. It can therefore result in complete confidentiality, integrity, and availability impact for the hosting service. ## Suggested remediation Treat the normalized `test` builtin family as dangerous before wildcard expansion and explicit builtin registration. For example, add `test` to `DANGEROUS_BUILTINS` so the existing prefix and family checks reject both `node:test` and `node:test/reporters`: ```js const DANGEROUS_BUILTINS = new Set([ // existing entries 'test' ]); ``` If test helpers must be exposed, provide a sandbox-local wrapper through `mock` or `override` that does not expose `run()`, process isolation, `execArgv`, or other host process controls. Recommended regression cases: - explicit `builtin: ['node:test']` - wildcard builtin configurations - `require('node:test')` - `require('node:node:test')` - `node:test/reporters` and prefixed variants - direct low-level builtin registration - attempts to pass `--eval`, `--require`, or `--import` through test-runner process options [vm2-node-test-ghsa-submission.zip](https://github.com/user-attachments/files/29930119/vm2-node-test-ghsa-submission.zip)

Advisory Timeline

  • First published October 1, 2026 (11 days ago).
  • Last revised October 1, 2026 — 0 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

npm
Update vm2 to 3.11.7 or later
npm install vm2@3.11.7

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: npm (1).

PackageEcosystemAffectedFixed In
vm2
npm
All versions3.11.7

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-693
    Protection Mechanism FailureMITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 9.9 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Frequently Asked Questions

What is CVE-2026-92948?
vm2: NodeVM builtin allowlist bypass via node:test.run() execArgv allows sandbox escape This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 9.9/10).
How do I check if my project is affected by CVE-2026-92948?
CVE-2026-92948 affects vm2. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-92948 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
9.9

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-qhwx-74w5-xhxq

Related CVEs

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies