highCVE-2026-47683Aug 17, 2026

CVE-2026-47683: vm2 bufferAllocLimit DoS Bypass via Buffer.concat and Buffer.from

Rohit Hatagale
AI Security Researcher, SecureLayer7

Sandbox code in vm2 can bypass the bufferAllocLimit cap by calling Buffer.concat or Buffer.from with a fake array length, allocating hundreds of megabytes of host memory in one synchronous call that…

Packagevm2
Ecosystemnpm
Affected<= 3.11.5
Fixed in3.11.6
CVE-2026-47683: vm2 bufferAllocLimit DoS Bypass via Buffer.concat and Buffer.from

The problem

The bufferAllocLimit option added in vm2 3.11.0 caps Buffer.alloc, Buffer.allocUnsafe, Buffer.allocUnsafeSlow, and the deprecated Buffer(N) forms. It does not wrap Buffer.concat or Buffer.from when called with an array-like object that has a numeric length property.

Both of those paths call into Node's internal C++ allocator with the attacker-supplied size before vm2 can inspect it. A single sandbox call can allocate 50+ MiB of host external memory synchronously. In Docker, Kubernetes, or Lambda environments this drives RSS up by hundreds of megabytes per call and OOMs the host process.

Proof of concept

A working proof-of-concept for CVE-2026-47683 in vm2, with the exact payload below.

javascript
'use strict';
const { VM, NodeVM } = require('vm2');

// Both VMs have the cap set to 1024 bytes.

// Bypass 1: Buffer.concat with explicit totalLength
const vm1 = new VM({ bufferAllocLimit: 1024 });
const buf1 = vm1.run('Buffer.concat([Buffer.from("a")], 50 * 1024 * 1024)');
console.log('concat bypass, got bytes:', buf1.length); // 52428800

// Bypass 2: Buffer.from with array-like fake length (no real array exists)
const vm2 = new VM({ bufferAllocLimit: 1024 });
const buf2 = vm2.run('Buffer.from({ length: 8 * 1024 * 1024 })');
console.log('from bypass, got bytes:', buf2.length); // 8388608

lib/setup-sandbox.js installs checkBufferAllocLimit at every wrapped allocation entry point (alloc, allocUnsafe, allocUnsafeSlow, and the BufferHandler apply/construct traps for deprecated Buffer(N)). Buffer.concat is not wrapped at all, so the sandbox-visible Buffer.concat is the raw bridge proxy of the host function.

It calls Node's internal Buffer.allocUnsafe(totalLength) directly, never touching the sandbox-side wrapper.

Buffer.from takes a separate code path when its argument is array-like. Node's fromArrayLike allocates a buffer of size argument.length before iterating to fill it. Since no real array of that length needs to exist first, the advisory's assumption that this path is 'bounded by source array size' is false.

The fix adds sandbox-side connect(...) wrappers for both paths that call checkBufferAllocLimit before delegating to the host, matching the pattern already used for the alloc family. CWE-770: Allocation of Resources Without Limits or Throttling.

The fix

Upgrade to vm2 3.11.6. That release adds checkBufferAllocLimit guards to Buffer.concat (summing totalLength or falling back to summing list element lengths) and to the array-like branch of Buffer.from, closing both uncapped host allocation paths.

Reporter not attributed.

References: [1][2][3]

Related research