Detect vm2 Native Code Execution via crypto.setEngine Sandbox Escape (CVE-2026-92939) in Splunk
Detects exploitation and presence of CVE-2026-92939, a critical (CVSS 9.9, CWE-114 Process Control) sandbox escape in the vm2 npm package versions >= 3.11.3 and <= 3.11.6. The vm2 crypto builtin proxy fails to restrict the native `crypto.setEngine()` call, allowing untrusted code executing inside the vm2 sandbox to load an attacker-controlled native engine shared object (.so/.dll). Loading the native module executes attacker code outside the JavaScript sandbox with full host privileges of the Node.js process, resulting in remote code execution. A public PoC is available via GHSA-46pr-c5wc-xffx. This detection surfaces runtime indicators of the escape (Node.js processes loading unexpected native modules via OpenSSL engine loading, child process spawns from Node runtimes hosting vm2, and anomalous dlopen of untrusted shared objects) as well as software-inventory evidence of vulnerable vm2 versions. Remediate by upgrading to vm2 >= 3.11.7 or migrating off vm2 (the project is deprecated).
MITRE ATT&CK
- Tactic
- Execution Privilege Escalation
SPL Detection Query
index=* (sourcetype="linux:audit" OR sourcetype="WinEventLog:Sysmon" OR sourcetype="sysmon")
| eval parent=lower(coalesce(ParentImage, parent_process_name, exe))
| eval child=lower(coalesce(Image, process_name, comm))
| where like(parent, "%node%")
| where match(child, "(sh|bash|dash|cmd\.exe|powershell\.exe|pwsh|openssl|gcc|cc|ld|whoami|id|curl|wget)$")
| stats count min(_time) as firstSeen max(_time) as lastSeen values(child) as children values(CommandLine) as cmdlines by host, parent, user
| convert ctime(firstSeen) ctime(lastSeen)
| sort - count Detects Node.js processes spawning shell, compiler, or reconnaissance children via Sysmon/auditd process-creation telemetry — the host-side manifestation of a vm2 crypto.setEngine native-code escape.
Data Sources
Required Sourcetypes
False Positives & Tuning
- Node applications shelling out legitimately (e.g. child_process usage in build tooling)
- CI runners compiling native npm modules with gcc/cc during install
- Legitimate use of openssl CLI invoked by a Node orchestration script
Other platforms for CVE-2026-92939
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 1Install vulnerable vm2 version (inventory detection)
Expected signal: npm install process events, file creation under /tmp/vm2-cve/node_modules/vm2, node process reading package.json
- Test 2Node process spawns shell child (escape payload simulation)
Expected signal: auditd execve showing node as parent of sh/id; Sysmon-equivalent process creation
- Test 3Node loads untrusted native module (dlopen simulation)
Expected signal: node process image/library load of /tmp/evil_engine.so outside node_modules; appears in /proc/<pid>/maps
References (6)
- https://github.com/patriksimek/vm2/security/advisories/GHSA-46pr-c5wc-xffx
- https://nvd.nist.gov/vuln/detail/CVE-2026-92939
- https://github.com/patriksimek/vm2/commit/aa146a77f859325e079f3bfbfe6d8309af483daa
- https://github.com/patriksimek/vm2/releases/tag/v3.11.7
- https://www.vulncheck.com/advisories/vm2-3.11.3-through-3.11.6-native-code-execution-via-crypto-setengine
- https://github.com/advisories/GHSA-46pr-c5wc-xffx
Response Playbook
Triage
- Confirm the host runs a Node.js application that embeds the vm2 package and determine its version via `npm ls vm2` / inspection of package-lock.json; versions >= 3.11.3 and <= 3.11.6 are vulnerable to CVE-2026-92939.
- Correlate the alerting Node.js process with the application it serves and establish whether that application accepts and evaluates untrusted/user-supplied JavaScript inside vm2 (the required precondition for exploitation).
- Examine the child process or loaded native module path flagged by the alert: determine whether the .so/.dll/.node file is a legitimate npm native addon or an attacker-staged artifact, including its on-disk location, hash, and signer.
- Review the parent Node process command line and recent application logs for the crypto.setEngine call pattern or errors referencing OpenSSL engine loading.
Containment
- Isolate the affected host from the network to prevent lateral movement and C2 from the escaped native payload.
- Kill the offending Node.js process and any child processes it spawned, and disable the service/pod until vm2 is upgraded to >= 3.11.7 or removed.
- Quarantine the suspicious native module/shared object and block its hash across the fleet.
Evidence Collection
- Capture the Node.js process memory and the full process tree (parent node + all children) before termination for forensic analysis.
- Collect the suspect native engine file (.so/.dll/.node), its filesystem metadata (timestamps, ownership), and compute cryptographic hashes.
- Preserve application and reverse-proxy logs showing the request/payload that reached the vm2 sandbox, plus package-lock.json documenting the vulnerable vm2 version.
Escalation Criteria
- !Escalate to incident response if a non-npm, unsigned native module was loaded by the Node process or if any child process performed reconnaissance, credential access, or outbound network connections.
- !Escalate if the affected application is internet-facing and accepts untrusted code, indicating probable active exploitation rather than a false positive.
- !Escalate to threat hunting if the same native-module-load or node-spawns-shell pattern appears on multiple hosts.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
The attacker-supplied native engine shared object (.so/.dll/.node) on disk and its load entry in /proc/<pid>/maps or Sysmon ImageLoad events - >
package-lock.json / node_modules/vm2/package.json showing version 3.11.3–3.11.6 - >
Application logs or stack traces referencing crypto.setEngine or OpenSSL ENGINE_by_id loading - >
Node.js process tree showing child processes uncharacteristic of a pure-JS workload
Tuning Guidance
Baseline which Node.js applications legitimately spawn child processes or load native addons (node-gyp .node modules) and allowlist those specific parent application paths and module directories. Restrict the match to production application hosts and exclude CI/build agents where gcc/cc/ld invocation by node during npm install is expected. Prioritize alerts where the loaded native module resides outside node_modules or is unsigned/unknown-hash, as those are the strongest escape indicators.
Hunting Queries
Hunts for Node.js processes spawning shells, compilers, or recon tooling across the fleet, surfacing vm2 escape activity beyond the initial alert.
DeviceProcessEvents | where InitiatingProcessFileName in~ ("node","node.exe","nodejs") | where FileName in~ ("sh","bash","openssl","gcc","cc","whoami","id","curl","wget") | summarize count() by DeviceName, FileName, ProcessCommandLine, bin(Timestamp,1h) index=* sourcetype="WinEventLog:Sysmon" OR sourcetype="linux:audit" | eval p=lower(coalesce(ParentImage,parent_process_name)) | where like(p,"%node%") | stats count values(Image) as children by host,user Atomic Red Team Tests
Installs vm2 3.11.6 to generate software-inventory evidence of the vulnerable version range for CVE-2026-92939.
Command
mkdir -p /tmp/vm2-cve && cd /tmp/vm2-cve && npm init -y >/dev/null 2>&1 && npm install [email protected] >/dev/null 2>&1 && node -e "console.log(require('/tmp/vm2-cve/node_modules/vm2/package.json').version)" Cleanup
rm -rf /tmp/vm2-cve Expected Telemetry
npm install process events, file creation under /tmp/vm2-cve/node_modules/vm2, node process reading package.json
Expected Detection
Software inventory / SCA flags [email protected] as within affected range >=3.11.3,<=3.11.6.
Simulates the post-escape behavior where native code loaded via setEngine spawns a host shell from the Node.js process.
Command
node -e "require('child_process').execSync('id > /tmp/vm2_escape_proof.txt')" Cleanup
rm -f /tmp/vm2_escape_proof.txt Expected Telemetry
auditd execve showing node as parent of sh/id; Sysmon-equivalent process creation
Expected Detection
Alert fires on Node.js parent spawning shell/recon child process.
Simulates loading an attacker-staged native engine module from a non-standard path, mimicking crypto.setEngine native code loading.
Command
cp /usr/lib/x86_64-linux-gnu/libz.so.1 /tmp/evil_engine.so 2>/dev/null; node -e "try{process.dlopen({exports:{}},'/tmp/evil_engine.so')}catch(e){console.log('load attempted:',e.message)}" Cleanup
rm -f /tmp/evil_engine.so Expected Telemetry
node process image/library load of /tmp/evil_engine.so outside node_modules; appears in /proc/<pid>/maps
Expected Detection
Alert fires on Node.js loading a native .so from an untrusted path outside standard runtime directories.