Severity by source
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
Primary rating from Vendor (https://github.com/patriksimek/vm2).
CVSS VectorVendor: https://github.com/patriksimek/vm2
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
Lifecycle Timeline
3Blast Radius
ecosystem impact- 88 npm packages depend on vm2 (4 direct, 84 indirect)
Ecosystem-wide dependent count for version 3.11.4.
DescriptionCVE.org
Summary
NodeVM supports excluding public network builtins from the wildcard builtin option. With this configuration direct access to http, https, http2, net, dgram, tls, dns, and dns/promises is blocked.
However, Node.js also exposes underscored internal HTTP builtins such as _http_client and _http_server. These are not blocked when the public modules are excluded.
Sandboxed code can use these internal builtins to make outbound HTTP requests and open listening HTTP sockets even though the public network modules are denied.
Note: This is not host RCE. It is a network capability bypass that can lead to SSRF-style access to internal services.
Details
The wildcard builtin expansion is based on Node.js builtin module names:
const BUILTIN_MODULES = (nmod.builtinModules || Object.getOwnPropertyNames(process.binding('natives')))
.filter(s=>!s.startsWith('internal/') && !DANGEROUS_BUILTINS.has(s));Public modules can be excluded with -name:
if (builtins.indexOf(`-${name}`) === -1) {
addDefaultBuiltin(res, name, hostRequire);
}But excluding http and net does not exclude internal siblings such as:
_http_client
_http_server
_tls_wrapThese internal modules expose network primitives.
Confirmed examples:
require('_http_client').ClientRequest(...)performs an outbound HTTP request to a host-local service whilehttpandnetare blocked.require('_http_server').Server(...).listen(...)opens a listening HTTP socket whilehttpandnetare blocked.
PoC
Tested on:
vm2: 3.11.2
Node.js: v25.9.0Run from the vm2 repository root:
node poc/internal-http-builtin-network-bypass.jsinternal-http-builtin-network-bypass.js
The PoC first confirms the intended restrictions work then bypasses them:
require("_http_client").ClientRequest(...)This performs an HTTP request to a host-local service and reads the response.
It also confirms:
require("_http_server").Server(...).listen(0)This opens a listening HTTP socket from inside the sandbox.
<img width="951" height="623" alt="Screenshot 2026-05-10 at 1 07 39 PM" src="https://github.com/user-attachments/assets/21bfb1ff-dd15-423a-92c4-0337cd07816c" />
Impact
An attacker who can run untrusted JavaScript inside NodeVM with this affected builtin configuration can regain network access even when the application attempted to block network modules.
This can allow SSRF-style access to localhost services, metadata endpoints, internal admin panels, or other network resources reachable from the host process.
Suggested fix
Treat underscored internal network modules as dangerous or link their availability to the public module they wrap.
At minimum, exclude related internal modules such as:
_http_agent
_http_client
_http_common
_http_incoming
_http_outgoing
_http_server
_tls_common
_tls_wrapAlternatively, deny underscored Node.js internals from wildcard builtin expansion by default.
AnalysisAI
Sandbox network isolation bypass in vm2 NodeVM (versions <= 3.11.3) allows untrusted JavaScript running in the sandbox to regain outbound and listening network access despite explicit exclusions of public network modules. Remote attackers (in the threat model where the application accepts untrusted code) can leverage Node.js's undocumented underscored builtins such as _http_client and _http_server to reach internal services, cloud metadata endpoints, and localhost-only admin panels. Publicly available exploit code exists (PoC published in the GHSA advisory), and a vendor-released patch is available in version 3.11.4.
Technical ContextAI
vm2 is a widely deployed Node.js sandboxing library (pkg:npm/vm2) used to execute untrusted JavaScript with controlled access to host capabilities. The NodeVM component exposes a builtin option supporting a '*' wildcard plus -name exclusions to allow most builtins while denying a specific subset. Internally, lib/builtin.js derives the wildcard set from require('module').builtinModules, filtering only names that start with internal/ or that appear in a DANGEROUS_BUILTINS denylist. Node.js, however, also exposes parallel underscored implementation modules (_http_client, _http_server, _http_agent, _http_common, _http_incoming, _http_outgoing, _tls_common, _tls_wrap, and several _stream_* siblings) that back the documented http, https, tls, and streams subsystems. Because -http and -net exclusions are pure string equality, they do not cascade to these siblings, so the wildcard expands to include them. The CWE-693 (Protection Mechanism Failure) classification correctly captures the root cause: the allowlist's source set and the embedder's mental model of what -http covers diverge.
RemediationAI
Apply the vendor-released patch by upgrading to vm2 3.11.4 (release: https://github.com/patriksimek/vm2/releases/tag/v3.11.4), which structurally fixes the issue in lib/builtin.js by filtering any builtin name starting with _ from the wildcard expansion source so '*' resolves only to documented public builtins (explicit opt-in, mock, and override paths remain functional). The upstream commit is https://github.com/patriksimek/vm2/commit/436053e30eecbabd487e2fd2959c137ac34e2bb1. If immediate upgrade is not possible, the actionable workaround is to stop using the wildcard pattern entirely and instead enumerate an explicit allowlist of builtins your sandboxed code actually requires (e.g., builtin: ['path', 'url', 'querystring']); this avoids the underscored sibling exposure but has the trade-off of breaking workloads that legitimately need other modules. As an interim measure, you can extend the exclusion list to enumerate every known underscored network sibling (_http_agent, _http_client, _http_common, _http_incoming, _http_outgoing, _http_server, _tls_common, _tls_wrap), but this is brittle since future Node.js releases may add new underscored builtins. Additionally, given vm2's broader history of sandbox escapes, consider migrating to a maintained alternative such as isolated-vm or running untrusted code in a separate process with OS-level network egress controls.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same weakness CWE-693 – Protection Mechanism Failure
View allVendor StatusVendor
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-36444
GHSA-r9pm-gxmw-wv6p