← Back to Feed CACHED · 2026-09-04 17:26:25 · CACHE_KEY CVE-2026-19534
CVE-2026-19534 · CWE-248 · Disclosed 2026-08-28

undici vulnerable to Denial of Service via unrequested WebSocket subprotocol

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

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.

"Client-side WebSocket crash requires your app to connect to attacker's server — not a typical attack path"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Attacker controls WebSocket endpoint

The attacker must operate a malicious WebSocket server or compromise an existing WebSocket endpoint that the victim's Node.js application connects to. Alternatively, the attacker can perform a man-in-the-middle attack on a plaintext ws:// connection. Without one of these positions, the attack chain cannot begin.
Conditions required:
  • Victim application uses undici WebSocket client to connect to an external endpoint
  • Attacker controls that endpoint OR can intercept plaintext ws:// traffic
Where this breaks in practice:
  • 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
STEP 02

Server sends unrequested Sec-WebSocket-Protocol header

During the WebSocket handshake, the server includes a 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.
Conditions required:
  • Malicious server crafts a single HTTP 101 response with an extra header
Where this breaks in practice:
  • Trivial for the attacker to execute once they control the server — no friction at this step
Detection/coverage: WAF or proxy inspection of WebSocket upgrade responses could flag unexpected subprotocol headers, but this is not a standard rule
STEP 03

Uncaught TypeError crashes Node.js process

The TypeError propagates through a microtask callback without a try/catch wrapper. Node.js treats unhandled exceptions in microtasks as fatal by default, terminating the process immediately. The crash is instantaneous and requires no further attacker action.
Conditions required:
  • Application does not have a global process.on('uncaughtException') handler that swallows the error
Where this breaks in practice:
  • 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
Detection/coverage: Application crash logs will show TypeError with stack trace pointing to undici WebSocket internals; APM tools (Datadog, New Relic) will flag the restart
STEP 04

Denial of service achieved

The victim's Node.js process exits. If the attacker can induce the victim to reconnect (which many WebSocket clients do automatically via reconnect logic), the crash-restart loop can be sustained, creating a persistent DoS. Without reconnect logic, it is a single crash followed by automatic recovery.
Conditions required:
  • Victim's reconnect logic automatically re-establishes the connection to the same malicious server
Where this breaks in practice:
  • 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
Detection/coverage: Repeated process restarts visible in orchestration dashboards (Kubernetes events, systemd journal); APM alerts on crash loops
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. Not listed in CISA KEV. No known campaigns or threat actor usage as of 2026-09-05.
Proof of conceptTrivial 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 scoreNot yet scored by FIRST (CVE too recent for EPSS model ingestion).
KEV statusNot listed. No CISA KEV entry.
CVSS vectorCVSS: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 versionsundici 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 versionsundici 6.28.1, 7.29.1, 8.10.2. Node.js patch releases bundling these versions expected in the next security release cycle.
Exposure dataundici 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).
Reportermanus-use (via GitHub Security Advisory). Fix by mcollina, reviewed by UlisesGascon.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.3/10)

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.

HIGH Vulnerability mechanics and affected versions
HIGH Client-side attack prerequisite assessment
MEDIUM Installed base using undici WebSocket (vs HTTP-only)
LOW EPSS and exploitation probability (no data available)

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.

05 · Compensating Control

What to do — in priority order.

  1. 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.
  2. 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.
  3. Use a WebSocket reconnect library with circuit breaker — Libraries like reconnecting-websocket with exponential backoff and max-retry limits prevent crash-restart loops from becoming a sustained DoS. The process still crashes once, but the loop breaks.
  4. 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.
What doesn't work
  • 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.
06 · Verification

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

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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
fi
07 · Bottom Line

If you remember one thing.

TL;DR
This is a niche client-side DoS in undici's WebSocket implementation that requires your application to connect outbound to an attacker-controlled server. At a reassessed MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day remediation window. Run 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

  1. GitHub Security Advisory GHSA-rfgv-xxqx-mfg5
  2. undici npm package
  3. undici Security Advisories
  4. Stack.watch undici 2026 vulnerabilities
  5. CISA Known Exploited Vulnerabilities Catalog
  6. FIRST EPSS API
  7. RFC 6455 §4.1 — WebSocket Opening Handshake
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.