Disclosure summary
### Summary Untrusted JavaScript running inside `new VM().run()` / `new NodeVM().run()` can bypass `vm.freeze()` / `vm.readonly()` and mutate a host object the embedder explicitly marked read-only - the documented contract is "prevent sandboxed scripts from adding, changing, or deleting properties". If the frozen host object has an accessor (get/set) own-property, the sandbox can read the host setter back out via `Object.getOwnPropertyDescriptor()` and call it directly; the call lands in `BaseHandler.apply` which unwraps the readonly proxy to the raw host object and runs the host setter against it. No non-default `VM`/`NodeVM` options are required; the only precondition is that the embedder froze an object whose shape includes an accessor property. A second route to the same sink exists via `__lookupSetter__`. ### PoC ```js // poc.js 'use strict'; const { VM } = require('vm2'); let _level = 'safe'; const hostConfig = Object.defineProperty({}, 'level', { get() { return _level; }, set(v) { _level = String(v); }, enumerable: true, configurable: true, }); const vm = new VM(); vm.freeze(hostConfig, 'cfg'); // Baseline - documented barriers hold: vm.run(`cfg.level = 'via-set';`); vm.run(
Source-specific records & product guidance
Sources retain their own attribution and scoring. Follow the original record to confirm affected versions, fixed releases, and configuration conditions.
GitHub Reviewed Security Advisories · GHSA-633r-hq9m-c4ff
Open original source · Updated Oct 01, 2026
vm2: vm.freeze()/vm.readonly() bypass via accessor descriptor
Source severity: MEDIUM / 0
| Ecosystem | Package | Affected range | First patched |
|---|---|---|---|
| npm | vm2 | >= 3.9.6, | 3.11.7 |
Original records & references
- NIST NVD record
- CVE Program record
- github.com — Reviewed advisory
PUBLISHED 2026-10-01T11:35:25-04:00
MODIFIED 2026-10-01T11:35:26-04:00
INGESTED 2026-10-06T11:45:02-04:00