It's like a booby-trapped phone number that only hurts you if you dial it
CVE-2026-19534 affects the undici HTTP/WebSocket client library bundled in Node.js 18+. When a Node.js application opens a WebSocket connection and the remote server responds with a Sec-WebSocket-Protocol header the client never requested, undici throws an uncaught TypeError in a microtask callback. Because the exception is unhandled, the entire Node.js process terminates immediately. The bug exists in undici versions 6.7.0–6.28.0, 7.0.0–7.29.0, and 8.0.0–8.10.1, and is fixed in 6.28.1, 7.29.1, and 8.10.2.
The vendor rates this HIGH at CVSS 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H), and on paper the vector looks clean: network-reachable, no auth, no interaction. But the vector is misleading. This is a client-side vulnerability — the attacker must control the WebSocket server the victim connects to, or must man-in-the-middle a plaintext ws:// connection. In practice, this means the attacker cannot just send a packet to crash your service; your application must be making outbound WebSocket connections to an endpoint the attacker controls. That prerequisite dramatically narrows real-world exploitability. The availability-only impact (process crash, no code execution, no data exfiltration) further limits blast radius, especially since Node.js deployments typically run behind process managers that auto-restart.
4 steps from start to impact.
Attacker controls WebSocket endpoint
ws:// connection. Without one of these positions, the attack chain cannot begin.- Victim application uses undici WebSocket client to connect to an external endpoint
- Attacker controls that endpoint OR can intercept plaintext ws:// traffic
- Most Node.js applications use undici for HTTP fetch, not WebSocket
- Enterprise deployments overwhelmingly use wss:// (TLS), blocking MITM
- Legitimate WebSocket endpoints are not trivially compromised
Server sends unrequested Sec-WebSocket-Protocol header
Sec-WebSocket-Protocol header in its HTTP 101 response, naming a subprotocol the client never offered. Per RFC 6455 §4.1, the client must fail the connection. Undici attempts to process this but the validation code throws an uncaught TypeError.- Malicious server crafts a single HTTP 101 response with an extra header
- Trivial for the attacker to execute once they control the server — no friction at this step
Uncaught TypeError crashes Node.js process
- Application does not have a global
process.on('uncaughtException')handler that swallows the error
- Many production Node.js apps use frameworks or process managers (pm2, systemd, Kubernetes) that auto-restart crashed processes within seconds
- Applications with robust error handling may catch uncaught exceptions globally
Denial of service achieved
- Victim's reconnect logic automatically re-establishes the connection to the same malicious server
- Process managers restart the application, often with backoff
- Circuit breaker patterns in well-architected services will stop reconnecting after repeated failures
- Impact is limited to availability of the single service — no lateral movement, no data compromise
The supporting signals.
| In-the-wild exploitation | None observed. Not listed in CISA KEV. No known campaigns or threat actor usage as of 2026-09-05. |
|---|---|
| Proof of concept | Trivial to reproduce — a minimal WebSocket server that adds Sec-WebSocket-Protocol: bogus to its 101 response will trigger the crash. No weaponized tooling or named PoC repos identified. |
| EPSS score | Not yet scored by FIRST (CVE too recent for EPSS model ingestion). |
| KEV status | Not listed. No CISA KEV entry. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — 7.5 HIGH. Availability-only impact. The AV:N is technically accurate (network-delivered) but the client-side prerequisite is not captured by the vector. |
| Affected versions | undici 6.7.0–6.28.0, 7.0.0–7.29.0, 8.0.0–8.10.1. Also affects Node.js 18.x/20.x/22.x/24.x builds bundling vulnerable undici versions. |
| Fixed versions | undici 6.28.1, 7.29.1, 8.10.2. Node.js patch releases bundling these versions expected in the next security release cycle. |
| Exposure data | undici has ~143M weekly npm downloads and is bundled in Node.js 18+ for fetch(). However, the WebSocket API surface is a small fraction of usage — most consumers use undici for HTTP, not WebSocket. |
| Disclosure date | ~2026-08-28 (based on GHSA-rfgv-xxqx-mfg5 publication). |
| Reporter | manus-use (via GitHub Security Advisory). Fix by mcollina, reviewed by UlisesGascon. |
noisgate verdict.
The single most decisive factor driving the downgrade is the client-side attack posture: the victim's application must initiate an outbound WebSocket connection to an attacker-controlled server, which inverts the typical network attack model and drastically narrows the reachable population. Combined with availability-only impact (process crash, no code execution or data access), the real-world risk does not justify a HIGH rating.
Why this verdict
- Client-side inversion: The CVSS vector says AV:N/PR:N, implying an attacker can remotely crash your server. In reality, the attacker must *be* the server (or MITM plaintext ws://). Your application must dial out to the attacker. This is a fundamental narrowing that CVSS cannot express.
- WebSocket usage fraction: undici has 143M weekly npm downloads, but the vast majority use it as the HTTP fetch engine bundled in Node.js. The WebSocket client API is a niche feature — likely <5% of the installed base actively uses undici WebSocket connections to external servers.
- Availability-only, auto-recoverable: Impact is a process crash. No code execution, no memory disclosure, no data exfiltration. Modern Node.js deployments run under process managers (pm2, systemd, Kubernetes) that restart within seconds. Circuit breakers stop reconnect loops.
- Role multiplier: undici runs inside Node.js application processes. In *low-value roles* (frontend BFF, API gateway proxying HTTP), the WebSocket path is unused — chain does not start. In *typical roles* (backend service consuming a real-time data feed via WebSocket), a crash causes brief service disruption (host-level blast radius, auto-recovered). In *high-value roles* (CI/CD runners, SIEM integrations, monitoring agents using WebSocket), the chain could succeed if the upstream WebSocket endpoint is compromised, but the outcome is still a recoverable process crash — not domain takeover, not supply-chain pivot, not data breach. No high-value role produces a fleet-scale or identity-scale outcome, so the floor is not triggered.
- No exploitation evidence: No KEV listing, no known campaigns, no EPSS score, no weaponized tooling. The bug is conceptually simple but requires a specific and unusual attacker position.
Why not higher?
A HIGH rating would require either active exploitation evidence or a realistic attack path where an unauthenticated remote attacker can crash victim services at scale. Here, the attacker cannot initiate the connection — the victim must connect outbound to the attacker's server. This prerequisite eliminates the vast majority of Node.js deployments from the reachable population. The availability-only impact with automatic recovery further caps severity.
Why not lower?
A LOW rating would undercount the risk for the subset of applications that do make outbound WebSocket connections to semi-trusted or user-influenced endpoints (e.g., webhook relay services, multi-tenant integrations). In those scenarios, an attacker who compromises or impersonates a WebSocket endpoint can reliably crash the consuming service with a single handshake response, with no authentication required. The trivial exploit complexity within the reachable population keeps this above LOW.
What to do — in priority order.
- Wrap WebSocket connections in global uncaught exception handlers — Add
process.on('uncaughtException', handler)to catch the TypeError and log it instead of crashing. This is a stopgap — the connection will still fail, but the process survives. Deploy as a code change within the 365-day noisgate remediation SLA. - Enforce wss:// (TLS) for all outbound WebSocket connections — Eliminates the MITM vector entirely. If your WebSocket endpoints support TLS (they should), ensure no
ws://URLs remain in configuration. This does not protect against a compromised legitimate server but removes one attack path. - Use a WebSocket reconnect library with circuit breaker — Libraries like
reconnecting-websocketwith exponential backoff and max-retry limits prevent crash-restart loops from becoming a sustained DoS. The process still crashes once, but the loop breaks. - Pin outbound WebSocket endpoints to known-good servers — If your application connects to external WebSocket services, allowlist the endpoints. Do not allow user-supplied or dynamically resolved WebSocket URLs without validation.
- WAF rules on inbound traffic — this is an outbound client-side vulnerability. Your WAF inspects incoming requests, not your application's outgoing WebSocket handshakes.
- Rate limiting on your server — the crash happens in your application acting as a WebSocket *client*, not as a server receiving connections. Inbound rate limits are irrelevant.
- Upgrading Node.js alone — if you install undici as a direct npm dependency (overriding the bundled version), upgrading Node.js won't fix it. You must also update the npm package.
Crowdsourced verification payload.
Run this on any host where a Node.js application uses undici. It checks the installed undici version(s) against the vulnerable ranges. No special privileges required — just access to the project directory. Example: bash check_cve_2026_19534.sh /opt/myapp
#!/usr/bin/env bash
# check_cve_2026_19534.sh — Detect CVE-2026-19534 vulnerable undici versions
# Usage: bash check_cve_2026_19534.sh <project_directory>
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
VULNERABLE=0
check_version() {
local ver="$1"
local major minor patch
IFS='.' read -r major minor patch <<< "$ver"
major=${major:-0}; minor=${minor:-0}; patch=${patch:-0}
if [[ $major -eq 6 ]] && [[ $minor -ge 7 ]]; then
if [[ $minor -lt 28 ]] || { [[ $minor -eq 28 ]] && [[ $patch -lt 1 ]]; }; then
return 1 # vulnerable
fi
fi
if [[ $major -eq 7 ]]; then
if [[ $minor -lt 29 ]] || { [[ $minor -eq 29 ]] && [[ $patch -lt 1 ]]; }; then
return 1 # vulnerable
fi
fi
if [[ $major -eq 8 ]]; then
if [[ $minor -lt 10 ]] || { [[ $minor -eq 10 ]] && [[ $patch -lt 2 ]]; }; then
return 1 # vulnerable
fi
fi
return 0 # patched or unaffected
}
# Check npm-installed undici
if [ -f "$PROJECT_DIR/node_modules/undici/package.json" ]; then
NPM_VER=$(node -e "console.log(require('$PROJECT_DIR/node_modules/undici/package.json').version)" 2>/dev/null || echo "")
if [ -n "$NPM_VER" ]; then
if check_version "$NPM_VER"; then
echo "[PATCHED] npm undici $NPM_VER is not vulnerable."
else
echo "[VULNERABLE] npm undici $NPM_VER is affected by CVE-2026-19534."
VULNERABLE=1
fi
fi
else
echo "[INFO] No npm undici found in $PROJECT_DIR/node_modules."
fi
# Check Node.js bundled undici
BUNDLED_VER=$(node -e "console.log(process.versions.undici || '')" 2>/dev/null || echo "")
if [ -n "$BUNDLED_VER" ]; then
if check_version "$BUNDLED_VER"; then
echo "[PATCHED] Bundled undici $BUNDLED_VER is not vulnerable."
else
echo "[VULNERABLE] Node.js bundled undici $BUNDLED_VER is affected by CVE-2026-19534."
VULNERABLE=1
fi
else
echo "[INFO] Could not detect bundled undici version (Node.js < 18?)."
fi
if [ $VULNERABLE -eq 1 ]; then
echo "\nResult: VULNERABLE"
exit 1
else
echo "\nResult: PATCHED"
exit 0
fiIf you remember one thing.
npm audit across your Node.js fleet to identify undici versions in the vulnerable range (6.7.0–6.28.0, 7.x before 7.29.1, 8.x before 8.10.2) and update to 6.28.1, 7.29.1, or 8.10.2. Prioritize any service that makes outbound WebSocket connections to external or semi-trusted endpoints — those are the only codepaths where this bug is reachable. For everything else, fold it into your next quarterly dependency update cycle. If you discover any service connecting via plaintext ws://, fix that independently — it's a bigger problem than this CVE.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.