{"id":"GHSA-m5q2-4fm3-vfqp","revision":null,"records":[{"revision":"275dbe93a2864520a39b4f9aca761e35","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-47135","aliases":[],"title":"vm2: Sandbox escape via unblocked cross-realm Symbol.for keys + missing bridge write-trap symbol checks","description":"vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps having no isDangerousCrossRealmSymbol key check, sandbox code can obtain real cross-realm symbols, write them to host objects, and control host-side behavior — verified with a full util.promisify hijack chain. This issue has been patched in version 3.11.4.","state":0,"publishedAt":"2026-06-12T14:14:42.022+00:00","modifiedAt":"2026-06-13T03:55:55.641+00:00","affected":[{"ecosystem":"Vendor product","name":"vm2","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"patriksimek\",\n                    \"product\": \"vm2\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 3.11.4\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N","score":8.7,"severity":"HIGH"}],"references":["https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqp","https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878","https://github.com/patriksimek/vm2/releases/tag/v3.11.4"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-47135","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-47135","identifiers":["CVE-2026-47135"]},"retained":false,"historicalAffected":[]},{"revision":"67c872f4853c4cb5a363a0dadf3b3b34","observedAt":"2026-11-07T10:39:47.475+00:00","statement":{"source":"euvd","id":"EUVD-2026-36442","aliases":["CVE-2026-47135","GHSA-m5q2-4fm3-vfqp"],"title":"vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps …","description":"vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps having no isDangerousCrossRealmSymbol key check, sandbox code can obtain real cross-realm symbols, write them to host objects, and control host-side behavior — verified with a full util.promisify hijack chain. This issue has been patched in version 3.11.4.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N","score":8.7,"severity":null}],"references":["https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqp","https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878","https://github.com/patriksimek/vm2/releases/tag/v3.11.4"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-36442","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Jun 12, 2026, 2:14:42 PM","dateUpdated":"Jun 13, 2026, 3:55:55 AM"},"relatedAdvisories":[{"id":"RHSA-2026:50850","title":"Red Hat Security Advisory: Red Hat Ansible Automation Platform 2.1 security update","vulnerabilityIds":["CVE-2026-9277","CVE-2026-43997","CVE-2026-43998","CVE-2026-43999","CVE-2026-44000","CVE-2026-44001","CVE-2026-44002","CVE-2026-44003","CVE-2026-44004","CVE-2026-44005","CVE-2026-44006","CVE-2026-44007","CVE-2026-44008","CVE-2026-44009","CVE-2026-45411","CVE-2026-47131","CVE-2026-47135","CVE-2026-47137","CVE-2026-47139","CVE-2026-47140","CVE-2026-47141","CVE-2026-47209","CVE-2026-48068","CVE-2026-48801","CVE-2026-59877"]},{"id":"RHSA-2026:33574","title":"Red Hat Security Advisory: Red Hat Developer Hub 1.9.6 release.","vulnerabilityIds":["CVE-2026-9277","CVE-2026-9673","CVE-2026-27145","CVE-2026-33811","CVE-2026-39820","CVE-2026-42033","CVE-2026-42035","CVE-2026-42039","CVE-2026-42041","CVE-2026-42043","CVE-2026-42044","CVE-2026-42338","CVE-2026-42499","CVE-2026-44486","CVE-2026-44487","CVE-2026-44488","CVE-2026-44492","CVE-2026-44494","CVE-2026-44495","CVE-2026-44496","CVE-2026-44724","CVE-2026-45736","CVE-2026-47131","CVE-2026-47135","CVE-2026-47137","CVE-2026-47139","CVE-2026-47140","CVE-2026-47141","CVE-2026-47208","CVE-2026-47209","CVE-2026-48779"]},{"id":"RHSA-2026:36754","title":"Red Hat Security Advisory: Red Hat Developer Hub 1.10.2 release.","vulnerabilityIds":["CVE-2026-6322","CVE-2026-6734","CVE-2026-9277","CVE-2026-9673","CVE-2026-9697","CVE-2026-12143","CVE-2026-12151","CVE-2026-24781","CVE-2026-27136","CVE-2026-39820","CVE-2026-42338","CVE-2026-42499","CVE-2026-44486","CVE-2026-44487","CVE-2026-44488","CVE-2026-44492","CVE-2026-44494","CVE-2026-44495","CVE-2026-44496","CVE-2026-45736","CVE-2026-47131","CVE-2026-47135","CVE-2026-47137","CVE-2026-47139","CVE-2026-47140","CVE-2026-47141","CVE-2026-47208","CVE-2026-47210","CVE-2026-48779"]}],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-36442","identifiers":["EUVD-2026-36442","CVE-2026-47135","GHSA-m5q2-4fm3-vfqp"]},"retained":false,"historicalAffected":[]},{"revision":"5d40b51b1f6f478993b2aedb5d32c995","observedAt":"2026-10-27T13:11:40.402+00:00","statement":{"source":"nvd","id":"CVE-2026-47135","aliases":[],"title":"vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps …","description":"vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps having no isDangerousCrossRealmSymbol key check, sandbox code can obtain real cross-realm symbols, write them to host objects, and control host-side behavior — verified with a full util.promisify hijack chain. This issue has been patched in version 3.11.4.","state":0,"publishedAt":"2026-06-12T15:16:28.007+00:00","modifiedAt":"2026-10-26T11:10:00.157+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N","score":8.7,"severity":"HIGH"}],"references":["https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878","https://github.com/patriksimek/vm2/releases/tag/v3.11.4","https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqp"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-47135","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-693"],"productCriteria":[],"sourceDates":{"published":"2026-06-12T15:16:28.007","lastModified":"2026-10-26T11:10:00.157"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-47135","identifiers":["CVE-2026-47135"]},"retained":false,"historicalAffected":[]},{"revision":"7592d06b46674e2d88ba1456a0a93747","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-m5q2-4fm3-vfqp","aliases":["CVE-2026-47135"],"title":"vm2 has a sandbox escape via unblocked cross-realm Symbol.for keys + missing bridge write-trap symbol checks","description":"## Summary\n\nvm2 3.11.2 `Symbol.for` override in `setup-sandbox.js` only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's `set`/`defineProperty`/`deleteProperty` traps having **no** `isDangerousCrossRealmSymbol` key check, sandbox code can obtain real cross-realm symbols, write them to host objects, and control host-side behavior — verified with a full `util.promisify` hijack chain.\n\n## Root Cause\n\n**1. Incomplete `Symbol.for` override** (`setup-sandbox.js:132-142`):\n\n```js\nSymbol.for = function (key) {\n    const keyStr = '' + key;\n    if (keyStr === 'nodejs.util.inspect.custom') return blockedSymbolCustomInspect;\n    if (keyStr === 'nodejs.rejection') return blockedSymbolRejection;\n    return originalSymbolFor(keyStr); // everything else passes through\n};\n```\n\nOnly `inspect.custom` and `rejection` are blocked. The following 7 Node.js internal symbols pass through as **real cross-realm symbols**:\n\n- `nodejs.util.promisify.custom`\n- `nodejs.stream.readable`\n- `nodejs.stream.writable`\n- `nodejs.stream.duplex`\n- `nodejs.stream.transform`\n- `nodejs.webstream.isClosedPromise`\n- `nodejs.webstream.controllerErrorFunction`\n\nNote: `bridge.js` `isDangerousCrossRealmSymbol` covers `promisify.custom` on **reads**, but the `Symbol.for` override in setup-sandbox does not block it at the source.\n\n**2. Missing symbol check in bridge write traps** (`bridge.js`):\n\nThe `get` trap (line 1148) and `ownKeys` trap (line 1541) both check `isDangerousCrossRealmSymbol(key)`, but `set` (line 1231), `defineProperty` (line 1427), and `deleteProperty` (line 1493) have **no such check**. Sandbox code can write/define/delete properties with dangerous symbol keys on any non-protected host object.\n\n**3. Incomplete filters in setup-sandbox.js**:\n\n`isDangerousSymbol()`, `Object.getOwnPropertyDescriptors` override, and `Object.assign` override only filter `inspect.custom` and `rejection` — missing `promisify.custom` and all stream/webstream symbols.\n\n## Verified Exploitation: util.promisify Hijack\n\n```js\nconst { VM } = require('vm2');\nconst util = require('util');\n\nconst vm = new VM();\nconst hostFn = function readFile(path, cb) { cb(null, 'real data'); };\nvm.setGlobal('hostFn', hostFn);\n\n// Sandbox writes promisify.custom to host function\nvm.run(`\n  const kPromisify = Symbol.for('nodejs.util.promisify.custom');\n  hostFn[kPromisify] = function(path) {\n    return Promise.resolve('HIJACKED by sandbox');\n  };\n`);\n\n// Host-side: promisified function now returns sandbox-controlled value\nconst asyncRead = util.promisify(hostFn);\nasyncRead('/etc/passwd').then(console.log);\n// Output: \"HIJACKED by sandbox\"\n```\n\n**Additional verified attacks:**\n\n- Writing `nodejs.stream.writable` to a host Readable stream, altering its duck-typing identity\n- `Object.assign` propagates unblocked symbols from sandbox source to host target\n- `Object.defineProperty` with unblocked symbol key succeeds on host objects\n- `delete hostObj[unblocked_symbol]` succeeds, removing host-set symbol properties\n\n## Impact\n\n- **Semantic confusion**: Sandbox controls host `util.promisify` behavior, host stream type checks, and WebStream internals for any non-frozen host object exposed to the sandbox.\n- **Data integrity**: Host code relying on promisified function results gets sandbox-controlled values.\n- **Defense bypass**: Combined with specific host API patterns, sandbox-provided fake streams could bypass host-side input validation.\n\nThis is not a direct RCE — the bridge still wraps sandbox functions crossing the boundary — but it grants the sandbox control over host-side control flow decisions that depend on these symbol-keyed properties.\n\n## Affected Versions\n\n- vm2 <= 3.11.2 (all 3.x versions)\n\n## Environment\n\n- Node.js v24.14.0\n- macOS (Darwin 25.4.0)\n\n## Suggested Fix\n\n1. **`setup-sandbox.js`**: Block all `nodejs.*` prefixed symbols:\n\n```js\nSymbol.for = function (key) {\n    const keyStr = '' + key;\n    if (keyStr.startsWith('nodejs.')) return Symbol(keyStr);\n    return originalSymbolFor(keyStr);\n};\n```\n\n2. **`bridge.js`**: Add check to write traps:\n\n```js\nset(target, key, value, receiver) {\n    if (isDangerousCrossRealmSymbol(key)) throw new VMError(OPNA);\n    // ...\n}\n```\n\n3. **`setup-sandbox.js`**: Sync `isDangerousSymbol`, `Object.getOwnPropertyDescriptors`, `Object.assign` to cover all dangerous symbols.","state":0,"publishedAt":"2026-05-29T17:44:32+00:00","modifiedAt":"2026-06-12T19:45:09.8408039+00:00","affected":[{"ecosystem":"npm","name":"vm2","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"3.11.4"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqp","https://nvd.nist.gov/vuln/detail/CVE-2026-47135","https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878","https://github.com/patriksimek/vm2","https://github.com/patriksimek/vm2/releases/tag/v3.11.4"],"sourceUrl":"https://github.com/advisories/GHSA-m5q2-4fm3-vfqp","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-m5q2-4fm3-vfqp","identifiers":["GHSA-m5q2-4fm3-vfqp","CVE-2026-47135"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-07T19:07:25.1127279+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-07T19:07:25.1127279+00:00","lastSuccessAt":"2026-11-07T19:07:25.259395+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:25.259396+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-bb5c9d5a08063ef076042e33dd72a7d0ffa4c4487efdcf3106e29ba55ec2ad57-0f6819d30115900023f4b20f99e508641b2007efdd91dc0cdc8e3f4191d4d221","complete":true,"records":420942,"lastAttemptAt":"2026-11-07T19:07:24.5330127+00:00","lastSuccessAt":"2026-11-07T19:07:24.4427471+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:24.5330127+00:00","snapshotPublishedAt":"2026-11-07T18:20:15+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-05809410d082491a9e6eb58bff15758d","complete":true,"records":13633,"lastAttemptAt":"2026-11-07T19:19:28.6430553+00:00","lastSuccessAt":"2026-11-07T19:19:28.637+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:19:28.637+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-07T19:07:25.1127279+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-07T19:07:25.1127279+00:00","lastSuccessAt":"2026-11-07T19:07:25.2602906+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:25.2602909+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-029d4c3fa5184934830a91e59f7a88f3","complete":true,"records":13645,"lastAttemptAt":"2026-11-07T19:07:38.2251716+00:00","lastSuccessAt":"2026-11-07T19:07:38.222+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:38.222+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-0eb4d6dde62dffacd040ad992d4fd5a65cd7d0dc5f5f4cfa8b41967fc6f9ca5f","complete":true,"records":9914,"lastAttemptAt":"2026-11-07T19:07:24.9680856+00:00","lastSuccessAt":"2026-11-06T20:10:36.6450506+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:24.9680856+00:00","snapshotPublishedAt":"2026-11-06T20:02:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-07T19:07:24.6882184+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:24.6882184+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-335633e78a15c9cde10a6025895b5617717087fb945489ae7e15d377bacf34a9","complete":true,"records":3055,"lastAttemptAt":"2026-11-07T19:07:25.0706377+00:00","lastSuccessAt":"2026-11-06T16:03:00.7615789+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:25.0706377+00:00","snapshotPublishedAt":"2026-11-06T16:02:48+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-40ad6183a951565ace1520a9b4d631e1d0bfb1d4bf7c5574c375032559f3ff53","complete":true,"records":231292,"lastAttemptAt":"2026-11-07T19:07:24.8613995+00:00","lastSuccessAt":"2026-11-07T10:29:00.4821259+00:00","error":null,"lastVerifiedAt":"2026-11-07T19:07:24.8613995+00:00","snapshotPublishedAt":"2026-11-07T09:32:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}