# NodeVM network builtin exclusions bypass via internal _http_client and _http_server

vm2 NodeVM's builtin exclusion blocks http/net but not underscored internals like _http_client and _http_server, letting sandboxed code make outbound requests and open sockets.

- Payout: Research
- Severity: high
- Program: vm2
- Found by: spbavarva
- Disclosed: 2026-05-29
- CVE: CVE-2026-47139
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-r9pm-gxmw-wv6p
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-r9pm-gxmw-wv6p
- Tags: area:oss domain:oss impact:internal-access kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:sandbox-escape vuln:ssrf

**Target:** NodeVM sandbox builtin module allowlist
**Root cause:** Wildcard builtin expansion filters only public module names and DANGEROUS_BUILTINS; underscored internal network modules (_http_client, _http_server, _tls_wrap) are not excluded when their public counterparts are denied.
**Steps:**
1. Configure NodeVM with builtins wildcard excluding `-http`, `-net`, etc.
2. From sandboxed code call `require('_http_client').ClientRequest(...)` to issue an outbound HTTP request to a host-local service and read the response.
3. Call `require('_http_server').Server(...).listen(0)` to open a listening HTTP socket from inside the sandbox.
4. Run `node poc/internal-http-builtin-network-bypass.js` on vm2 3.11.2 / Node v25.9.0 to confirm restrictions then bypass.
**How found:** Noticed the wildcard builtin expansion enumerates Node.js builtin module names and only filters public names plus a DANGEROUS_BUILTINS set; hypothesized underscored internal siblings of blocked modules remained reachable and tested _http_client/_http_server.
**Exploitation:** Attacker with code execution inside NodeVM under a network-restricted builtin config regains outbound HTTP and listening socket capability, enabling SSRF-style access to localhost services, cloud metadata endpoints, and internal admin panels reachable from the host process.
**Insight:** When auditing sandbox/module allowlists, enumerate the runtime's full builtin list including underscore-prefixed internals; blocking a public module rarely blocks its internal implementation modules that expose the same primitives.

## Proof of concept (copied exactly from the original report)

**Bypass via _http_client ClientRequest**

```
require("_http_client").ClientRequest(...)

This performs an HTTP request to a host-local service and reads the response.
```

**Bypass via _http_server listen**

```
require("_http_server").Server(...).listen(0)

This opens a listening HTTP socket from inside the sandbox.
```

