Oct 1, 2026·6 min read·5 visits
A critical sandbox escape in vm2 (versions >=3.9.6 to <=3.11.6) allows attackers to execute arbitrary system commands on the host by leveraging a prefix-stripping flaw to import the 'node:test' core module on Node.js 24+.
CVE-2026-92948 is a critical sandbox escape vulnerability in the vm2 library affecting versions 3.9.6 through 3.11.6 when executed on Node.js 24 and newer. The vulnerability allows an attacker to bypass built-in module blocking defenses by double-prefixing a restricted module name (such as node:node:test). This permits the loading of the node:test module, whose test runner execution can be leveraged to execute arbitrary shell commands outside the VM sandbox.
The vm2 library is a widely utilized Node.js library designed to run untrusted code in a sandboxed virtual machine environment. To prevent untrusted scripts from accessing the host file system, network, or process spawning APIs, vm2 intercepts module resolution. It implements a strict blocklist of core Node.js modules, categorizing them as dangerous and preventing their import.
Historically, standard system administrative modules such as fs, child_process, and cluster were explicitly blocked. However, the introduction of the stable native test runner (node:test) in modern Node.js versions introduced a new attack surface. This testing module is capable of launching separate process-isolated host tasks, which can be manipulated to achieve host-realm code execution.
When vm2 runs on Node.js version 24 or newer, the module loading mechanism fails to correctly normalize prefixes. By providing a double-prefixed import string, an attacker can bypass the signature-based verification blocks. This exposes the unconstrained native node:test API directly inside the virtual environment.
The root cause lies in how vm2 attempts to prevent bypasses involving the node: scheme prefix. Node.js allows core modules to be imported using the node: prefix, such as require('node:fs') instead of require('fs'). To address this, the vm2 module loader in lib/setup-node-sandbox.js stripped a single instance of the node: prefix before performing validation against the list of dangerous builtins.
An attacker can supply a module specifier string with two prefixes, such as node:node:test. When parsed, the validation mechanism only removes the first prefix, leaving node:test to be processed. The validator incorrectly assumed that any remaining string after one stripping operation would either be a non-builtin or would fail native resolution.
vm2 does not process nested prefixes recursively, which is the core architectural flaw. The native Node.js resolver is highly permissive and successfully resolves node:node:test to the underlying node:test module. Because node:test was not defined within the DANGEROUS_BUILTINS blocklist in vulnerable versions, the import is allowed. The sandbox is then provisioned with a direct proxy to the host's actual test execution context.
An analysis of the vulnerability before the release of version 3.11.7 reveals that the normalization function was vulnerable to nested prefix evasion. The original code only performed a single prefix check:
// Vulnerable prefix normalization logic
function isDangerousBuiltin(key) {
if (typeof key !== 'string') return false;
if (key.startsWith('node:')) key = key.slice(5);
if (DANGEROUS_BUILTINS.has(key)) return true;
const slash = key.indexOf('/');
if (slash > 0 && DANGEROUS_BUILTINS.has(key.slice(0, slash))) return true;
}To remediate this, commit 415339f698f0d52d3c5ad358b12b79c8072d5b4b modified the function to run a recursive while loop. This design modification ensures that all nested or repeated instances of the node: prefix are stripped before the blocklist validation occurs:
// Patched prefix normalization logic
function isDangerousBuiltin(key) {
if (typeof key !== 'string') return false;
// Strip ALL leading node: prefixes recursively
while (key.startsWith('node:')) key = key.slice(5);
if (DANGEROUS_BUILTINS.has(key)) return true;
const slash = key.indexOf('/');
if (slash > 0 && DANGEROUS_BUILTINS.has(key.slice(0, slash))) return true;
}Additionally, the developers appended test to the DANGEROUS_BUILTINS set in lib/builtin.js. This ensures that even if the prefix is bypassed, the test runner module is blocked by default.
Exploitation requires that the host application runs vm2 on Node.js version 24+ and configures the sandbox to permit the node:test module or use a wildcard allowlist. Once inside the sandbox, the attacker cannot import fs or child_process directly as those are strictly blocked. Instead, the attacker issues a request for the double-prefixed node:node:test module.
After successfully loading the node:test module proxy, the attacker invokes the test.run() method. This API supports process-isolated test execution and is executed directly within the host context, rather than the VM context. The API accepts an options object containing the execArgv array, which specifies command-line arguments to be forwarded to the child process.
By supplying the --eval command-line flag inside execArgv, the attacker instructs the spawned host Node.js process to execute arbitrary JavaScript. This execution occurs outside the sandbox boundaries, running with the full privileges of the parent process.
The security impact of CVE-2026-92948 is critical, resulting in complete host compromise. Successful exploitation bypasses all security controls implemented by the virtual machine environment. The attacker gains the ability to execute arbitrary code, modify host files, and establish reverse shells, effectively running commands as the user operating the parent Node.js application.
The vulnerability is tracked under CVSS v3.1 with a base score of 9.9. The vector string is CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H, highlighting that the scope has changed (S:C), meaning the exploitation of the sandbox directly affects the security of the host system.
The EPSS score is currently evaluated at 0.00654, which suggests low active exploitation in widespread campaigns, but public proof-of-concept availability raises the likelihood of targeted exploit attempts. This vulnerability represents a complete failure of the primary protection mechanism (CWE-693) of the sandbox.
The primary remediation path is to upgrade the vm2 dependency to version 3.11.7 or later. This version contains the recursive prefix stripping update and blocks the test module globally. However, because the vm2 project is officially deprecated and is no longer actively maintained, users should migrate to modern alternative sandbox architectures.
For robust isolation, applications should migrate to isolated-vm. This library runs untrusted scripts in separate V8 isolates, providing strong isolation and preventing access to Node.js builtins. Alternatively, running untrusted code in containerized environments, such as Docker or gVisor, ensures that sandbox escapes do not result in a compromise of the underlying host operating system.
If immediate software upgrading is not possible, the sandbox configuration must be modified. Explicitly remove any wildcard allowlists, such as builtin: ['*']. Ensure that only strictly necessary, non-dangerous builtins are permitted within the NodeVM instantiation parameters.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
vm2 Patrik Šimek | >= 3.9.6, <= 3.11.6 | 3.11.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-693 |
| Attack Vector | Network |
| CVSS Score | 9.9 (Critical) |
| EPSS Score | 0.00654 |
| Impact | Complete Sandbox Escape & Host Remote Code Execution |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
The product does not use or incorrectly implements a protection mechanism, allowing attackers to bypass isolation boundaries.
CVE-2026-92950 (GHSA-jxxv-8r27-vm4p) is a critical sandbox escape vulnerability in the command-line interface of the vm2 library prior to version 3.11.7. The flaw allows untrusted scripts to bypass sandbox constraints and execute arbitrary system commands with the privileges of the host process by exploiting insecure default configurations of the module resolver.
A high-severity sandbox escape and state corruption vulnerability exists in the vm2 library (versions 3.11.4 through 3.11.6). The vulnerability is caused by an incomplete blocklist of Node.js-internal registered symbols crossing the sandbox-host bridge boundary. Specifically, the filters in `lib/setup-sandbox.js` and write traps in `lib/bridge.js` omitted the symbols `nodejs.stream.disturbed` and `nodejs.stream.errored`, allowing untrusted code within the sandbox to corrupt host-realm stream state checks.
An architectural evaluation of CVE-2026-73607 in the SiYuan personal knowledge management system. This technical advisory details a Missing Authorization (CWE-862) vulnerability in the Go-based backend kernel, specifically within the outline storage API endpoint. Under certain configurations, authenticated low-privilege users can query metadata, heading structures, and block hierarchies of restricted documents.
An information disclosure vulnerability (CWE-862) in the SiYuan Note platform before version v3.7.4 allows anonymous or unprivileged readers to obtain a complete list of bookmark labels globally across all workspaces and notebooks by querying the `/api/attr/getBookmarkLabels` API endpoint.
An authorization bypass and information leakage vulnerability exists in the SiYuan database module. Unauthenticated users can query the getAttributeViewSearchTarget API endpoint using target block identifiers to extract private content.
CVE-2026-76504 is a critical vulnerability in the web-based management console of Cisco Catalyst SD-WAN Manager. Due to improper normalization and handling of hex/percent-encoded sequences (CWE-177) within incoming request URIs, remote, unauthenticated attackers can bypass administrative authentication controls. Successful exploitation permits full remote administrative command execution on the SD-WAN management plane, threatening the integrity and availability of the managed network fabric.