Summary
vm2's current host-intrinsic prototype protection is incomplete. The fix for GHSA-vwrp-x96c-mhwq blocks sandbox writes into classic host intrinsics such as Object.prototype, Array.prototype, and Function.prototype, but current head still lets sandbox code in a default VM reach and mutate host Uint8Array.prototype, %TypedArray%.prototype, and ArrayBuffer.prototype.
After VM.run() returns, normal host typed-array and ArrayBuffer objects observe attacker-controlled properties and methods installed by the sandbox.
Technical Details
The existing mitigation relies on protectedHostObjects in lib/bridge.js. That set is populated from otherGlobalPrototypes, which is built from a fixed inventory of classic globals:
const globalsList = [
'Number', 'String', 'Boolean', 'Date', 'RegExp', 'Map', 'WeakMap',
'Set', 'WeakSet', 'Promise', 'Function'
];
The inventory omits typed-array and ArrayBuffer intrinsics. Sandbox code can still reuse the host-prototype walking primitive from the prior public advisory:
const lookupGetter = ({}).__lookupGetter__;
const apply = Buffer.apply;
const protoGetter = apply.apply(lookupGetter, [Buffer, ['__proto__']]);
const hostBuffer = Buffer.from([1]);
const hostBufferPrototype = protoGetter.call(hostBuffer);
const hostUint8ArrayPrototype = protoGetter.call(hostBufferPrototype);
const hostTypedArrayPrototype = protoGetter.call(hostUint8ArrayPrototype);
const hostArrayBufferPrototype = protoGetter.call(hostBuffer.buffer);
Those objects are not sandbox-local. Inside the sandbox, hostUint8ArrayPrototype === Uint8Array.prototype, hostTypedArrayPrototype === Object.getPrototypeOf(Uint8Array.prototype), and hostArrayBufferPrototype === ArrayBuffer.prototype are all false. Because the objects are not in protectedHostObjects, bridge writes are forwarded into the real host objects.