# [CRIT] [GHSA / CRITICAL] CVE-2026-47429: When Vitest UI server is listening, arbitrary file can be read and executed

**Source:** GitHub Security Advisories
**Published:** 2026-06-01
**Article:** https://github.com/advisories/GHSA-5xrq-8626-4rwp

## Threat Profile

When Vitest UI server is listening, arbitrary file can be read and executed

### Summary
Arbitrary file can be read on Windows when Vitest UI server is listening, especially when exposed to the network.

### Impact
Only users that match either of the following conditions are affected:

- explicitly exposes the Vitest UI server to the network (using `--api.host` or [`api.host` config option](https://vitest.dev/config/api.html))
- running the Vitest UI or Browser Mode on Windows

### Details
The A…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-47429`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1204.002** — User Execution: Malicious File
- **T1574** — Hijack Execution Flow
- **T1083** — File and Directory Discovery
- **T1006** — Direct Volume Access
- **T1059.001** — Command and Scripting Interpreter: PowerShell
- **T1059.003** — Command and Scripting Interpreter: Windows Command Shell
- **T1133** — External Remote Services

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Vitest UI server launched with non-loopback --api.host / --host (CVE-2026-47429 exposure)

`UC_157_2` · phase: **weapon** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.process_name IN ("node.exe","npm.exe","yarn.exe","pnpm.exe","npx.exe") AND Processes.process="*vitest*" AND (Processes.process="*--ui*" OR Processes.process="*--browser*") AND (Processes.process="*--api.host*" OR Processes.process="*--host*" OR Processes.process="*api.host*") by Processes.dest Processes.user Processes.parent_process_name Processes.process Processes.process_id | `drop_dm_object_name(Processes)` | rex field=process "(?i)--(?:api\.)?host(?:[= ])(?<host_arg>[^\s"]+)" | where NOT match(host_arg,"(?i)^(127\.0\.0\.1|localhost|::1|0\.0\.0\.0$)") | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("node.exe","npm.exe","yarn.exe","pnpm.exe","npx.exe")
   or InitiatingProcessFileName in~ ("node.exe","npm.exe","yarn.exe","pnpm.exe","npx.exe")
| where ProcessCommandLine has "vitest"
| where ProcessCommandLine has_any ("--ui","--browser")
| where ProcessCommandLine has_any ("--api.host","--host","api.host")
| extend HostArg = extract(@"(?i)--(?:api\.)?host(?:[= ])(\S+)", 1, ProcessCommandLine)
| where isnotempty(HostArg) and HostArg !in~ ("127.0.0.1","localhost","::1")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, HostArg, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName
| order by Timestamp desc
```

### Path-traversal exploit hitting Vitest /__vitest_attachment__ endpoint (CVE-2026-47429 PoC)

`UC_157_3` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Web.Web where (Web.url="*__vitest_attachment__*" OR Web.url="*__vitest__*" OR Web.uri_path="*__vitest_attachment__*") AND (Web.url="*%3F%5C..%5C*" OR Web.url="*%3F\\..\\*" OR Web.url="*?\\..\\*" OR Web.url="*%3F/..*" OR Web.url="*\\?\\..*") by Web.dest Web.dest_port Web.src Web.user Web.url Web.status Web.http_user_agent Web.http_method | `drop_dm_object_name(Web)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where RemotePort == 51204 or LocalPort == 51204 or RemoteUrl has "__vitest"
| where isnotempty(RemoteUrl)
| where RemoteUrl has_any ("__vitest_attachment__","__vitest__")
| where RemoteUrl matches regex @"(?i)(%3F%5C|%3F/|\?\\|\?/)\.\.[\\/]"
| project Timestamp, DeviceName, ActionType, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName, LocalIP, LocalPort, RemoteIP, RemotePort, RemoteUrl
| order by Timestamp desc
```

### Post-exploit shell spawned by Vitest node.exe via rerun / saveTestFile (CVE-2026-47429)

`UC_157_4` · phase: **exploit** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name="node.exe" AND Processes.parent_process="*vitest*" AND Processes.process_name IN ("cmd.exe","powershell.exe","pwsh.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","regsvr32.exe","bitsadmin.exe","certutil.exe","curl.exe","wget.exe","net.exe","whoami.exe","hostname.exe","systeminfo.exe") by Processes.dest Processes.user Processes.parent_process Processes.process Processes.process_name Processes.process_id | `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "node.exe"
| where InitiatingProcessCommandLine has "vitest"
| where FileName in~ ("cmd.exe","powershell.exe","pwsh.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","regsvr32.exe","bitsadmin.exe","certutil.exe","curl.exe","wget.exe","net.exe","whoami.exe","hostname.exe","systeminfo.exe","nslookup.exe")
| where AccountName !endswith "$"
// Reduce FP: vitest legitimately launches node.exe worker children — only flag non-node children
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName, SHA256
| order by Timestamp desc
```

### Inbound TCP connection to Vitest UI port 51204 from non-loopback source

`UC_157_5` · phase: **delivery** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Network_Traffic.All_Traffic where All_Traffic.dest_port=51204 AND All_Traffic.transport="tcp" AND All_Traffic.action="allowed" AND NOT (All_Traffic.src IN ("127.0.0.1","::1","0.0.0.0")) AND NOT cidrmatch("127.0.0.0/8", All_Traffic.src) by All_Traffic.src All_Traffic.dest All_Traffic.dest_port All_Traffic.app | `drop_dm_object_name(All_Traffic)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where LocalPort == 51204 and Protocol == "Tcp"
| where ActionType in ("InboundConnectionAccepted","ConnectionSuccess","ListeningConnectionCreated")
| where RemoteIPType != "Loopback" and RemoteIP !in ("127.0.0.1","::1","")
| where InitiatingProcessFileName in~ ("node.exe","npm.exe","yarn.exe","pnpm.exe")
| summarize FirstSeen=min(Timestamp), LastSeen=max(Timestamp), ConnCount=count(), RemoteIps=make_set(RemoteIP, 20)
          by DeviceName, LocalIP, LocalPort, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by FirstSeen desc
```

### Article-specific behavioural hunt — [GHSA / CRITICAL] CVE-2026-47429: When Vitest UI server is listening, arbitrary

`UC_157_1` · phase: **install** · confidence: **High**

**Splunk SPL (CIM):**
```spl
``` Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-47429: When Vitest UI server is listening, arbitrary ```
| tstats `summariesonly` count earliest(_time) AS firstTime latest(_time) AS lastTime
    from datamodel=Endpoint.Processes
    where (Processes.process_path="*C:\path\to\project\*")
    by Processes.dest, Processes.user, Processes.process_name,
       Processes.process, Processes.parent_process_name, Processes.process_path
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| append [
| tstats `summariesonly` count
    from datamodel=Endpoint.Filesystem
    where Filesystem.action IN ("created","modified")
      AND (Filesystem.file_path="*C:\path\to\project\*")
    by Filesystem.dest, Filesystem.user, Filesystem.process_name,
       Filesystem.file_path, Filesystem.file_name
| `drop_dm_object_name(Filesystem)`
]
```

**Defender KQL:**
```kql
// Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-47429: When Vitest UI server is listening, arbitrary
// Hunts the actual binaries / paths / commandline fragments named
// in the article instead of a generic technique-class template.
DeviceProcessEvents
| where Timestamp > ago(30d)
| where (FolderPath has_any ("C:\path\to\project\"))
| project Timestamp, DeviceName, AccountName, FileName,
          FolderPath, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc

// File-creation events for the named binaries / paths
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated","FileModified")
| where (FolderPath has_any ("C:\path\to\project\"))
| project Timestamp, DeviceName, AccountName, FolderPath,
          FileName, ActionType, InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-47429`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 6 use case(s) fired, 8 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
