← Back to Feed CACHED · 2026-09-04 16:46:07 · CACHE_KEY CVE-2026-85014
CVE-2026-85014 · CWE-248 · Disclosed 2026-06-01

undici vulnerable to Denial of Service via WebSocketStream unclean close

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

Like leaving the crash-test dummy in the driver's seat — the car only wrecks if you steer it into the wall yourself

CVE-2026-85014 is an uncaught-exception (CWE-248) denial-of-service in undici's WebSocketStream implementation. When a Node.js application initiates a WebSocketStream connection and the remote server drops the TCP socket without completing the WebSocket close handshake (an "unclean close"), the #onSocketClose callback attempts to read this.#parser.closingInfo before the parser has been initialized. The resulting TypeError propagates unhandled, crashing the Node.js process. The bug affects applications that use the newer WebSocketStream API — not the older new WebSocket(…) constructor — and specifically requires the *client* to connect to a server under attacker influence. Affected versions span undici 7.x prior to the WebSocketStream close-handling fix (aligned with Node.js v24 line); the 6.x branch is unaffected because WebSocketStream was not backported to it.

The vendor's MEDIUM / 5.9 rating is *fair but slightly generous*. The CVSS vector already encodes AC:H, reflecting the need for specific conditions, but it doesn't capture two real-world narrowing factors: (1) WebSocketStream adoption is a small fraction of all undici WebSocket usage — most applications use the standard WebSocket class, and (2) the crash is a single-process DoS that is auto-recoverable under any modern process manager (PM2, systemd, Kubernetes liveness probe). noisgate trims the effective score to 4.5 while keeping the MEDIUM bucket.

"WebSocketStream DoS requires victim to dial an attacker-controlled server — low real-world exposure."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a target Node.js service using WebSocketStream

The attacker locates a Node.js application that uses new WebSocketStream(url) to connect outbound. This is the critical prerequisite — the victim application must *initiate* the connection to a server the attacker controls or can compromise. Applications that only *accept* inbound WebSocket connections (typical server pattern) are not affected.
Conditions required:
  • Target application uses undici WebSocketStream API (not standard WebSocket)
  • Target connects outbound to an endpoint the attacker can influence
Where this breaks in practice:
  • WebSocketStream is a newer, less-adopted API; most Node.js WebSocket code uses ws, socket.io, or undici's WebSocket class
  • Applications rarely connect to fully untrusted WebSocket endpoints without URL allowlisting
STEP 02

Attacker-controlled server accepts the WebSocket upgrade

The attacker stands up a WebSocket server that completes the HTTP upgrade handshake normally, establishing a live connection. No special payloads or authentication bypass is needed at this stage — the connection succeeds cleanly.
Conditions required:
  • Attacker controls the WebSocket server endpoint (own infrastructure, DNS hijack, or SSRF to redirect)
Where this breaks in practice:
  • DNS hijack or SSRF is a separate, higher-difficulty prerequisite that compounds the attack cost
Detection/coverage: Network-layer anomaly detection (unexpected outbound WebSocket destinations) can flag this step.
STEP 03

Server performs unclean TCP close before parser initialization completes

The attacker's server abruptly resets or closes the TCP connection during the narrow window after the upgrade response is sent but before #onConnectionEstablished() assigns the parser. This leaves this.#parser as undefined. The timing window is narrow, which is why the CVSS vector carries AC:H.
Conditions required:
  • Attacker must time the TCP reset to land in the initialization window
Where this breaks in practice:
  • The race window is small; many attempts may result in a normal connection error rather than the crash path
  • Network latency and OS TCP stack behavior add non-determinism
STEP 04

Uncaught TypeError crashes the Node.js process

When the socket closes, #onSocketClose() fires and tries to read this.#parser.closingInfo. Since the parser is undefined, a TypeError is thrown. Because undici does not wrap this call in a try/catch and does not use a domain or unhandledRejection handler, the exception is fatal — the process exits with code 1. Under Kubernetes or PM2, the process restarts within seconds.
Conditions required:
  • No application-level uncaughtException handler catches TypeError
Where this breaks in practice:
  • Most production Node.js deployments run behind a process manager that auto-restarts on crash
  • A global process.on('uncaughtException', …) handler — common in production — swallows this crash entirely
Detection/coverage: Application crash logs and process-restart metrics (e.g., Kubernetes CrashLoopBackOff alerts) surface this immediately.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No public reports of active exploitation. Not listed in CISA KEV.
Proof-of-conceptNo public weaponized PoC. The triggering condition (server-side unclean close during init window) is documented in undici issue #4732 with a reproduction scenario, but no standalone exploit tool exists.
EPSSEstimated < 1% probability of exploitation in 30 days (below 20th percentile), consistent with similar undici DoS CVEs (CVE-2026-2229 EPSS 0.49%, CVE-2026-1526 EPSS ~0.1%).
KEV statusNot listed. No CISA KEV entry as of 2026-09-05.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H — Network-reachable but high attack complexity (race window), availability-only impact, no scope change. The AC:H drives the 5.9 score down from the 7.5 that similar AC:L undici WebSocket bugs receive.
Affected versionsundici 7.x series (WebSocketStream implementation) prior to the close-handling fix. The 6.x branch does not ship WebSocketStream. The 8.x branch likely inherits the fix from the 7.x patch.
Fixed versionsundici 7.24.0 (or later patch release addressing WebSocketStream lifecycle). Node.js v24.x users should update the bundled undici or upgrade Node.
Scanning / exposure dataundici has ~150M+ weekly npm downloads, but the vulnerable surface is limited to the subset using WebSocketStream outbound connections — estimated at < 1% of the install base based on API novelty.
Disclosure date~2026 (aligned with Node.js v24 / undici 7.18+ timeframe, per issue #4732).
Reporting researcherCommunity-reported via GitHub issue tracker; fix delivered in PR #4748.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (4.5/10)

The single most decisive downgrade factor is the extremely narrow exposure population: only applications using the WebSocketStream API (not standard WebSocket) that also connect outbound to attacker-influenced servers are reachable, representing well under 1% of undici's installed base. The availability-only impact (process crash) is auto-recoverable in any production deployment using a process supervisor.

MEDIUM Vulnerability mechanics and affected API surface
LOW Exact affected / fixed version boundaries (CVE not in NVD)
HIGH No active exploitation or KEV listing

Why this verdict

  • Narrow API surface: WebSocketStream is a newer, less-adopted API. The overwhelming majority of Node.js WebSocket usage goes through ws, socket.io, or undici's standard WebSocket class — none of which are affected.
  • Attacker-influenced server required: The victim app must *initiate* the WebSocket connection to an endpoint the attacker controls or can redirect to (via DNS hijack / SSRF). Server-side WebSocket listeners — the dominant pattern — are not vulnerable.
  • Race condition (AC:H): The TCP close must land in the narrow initialization window before the parser is assigned. This is non-deterministic and many attempts will fail silently.
  • Auto-recoverable crash: Process managers (PM2, systemd, Kubernetes) restart the process in seconds. The blast radius is a brief availability blip, not persistent compromise.
  • Role multiplier: undici ships with Node.js (~150M weekly downloads), so the *theoretical* install base is enormous. However, WebSocketStream-based outbound connections are vanishingly rare in high-value roles. In CI/CD pipelines, API servers, and backend services, the standard WebSocket or HTTP client paths dominate. No high-value-role scenario (IdP, hypervisor, PAM, backup, EDR) canonically relies on undici WebSocketStream outbound connections. The blast radius in any deployment is single-process DoS — it does not escalate to host, domain, or fleet compromise. The floor rule does not elevate this beyond MEDIUM.

Why not higher?

Elevating to HIGH would require either active exploitation evidence, a broader affected API surface, or an impact beyond single-process availability disruption. None of these conditions are met. The AC:H race window, the requirement for an attacker-controlled server destination, and the auto-recoverability of the crash all argue against a higher rating.

Why not lower?

Dropping to LOW would undercount the fact that this *is* a remotely triggerable, unauthenticated process crash with no user interaction required. If a vulnerable application does connect to untrusted WebSocket endpoints (e.g., a proxy, aggregator, or federation service), the crash is reliable enough after repeated attempts. The 4.5 score preserves the signal that this bug deserves a patch, just not an emergency one.

05 · Compensating Control

What to do — in priority order.

  1. Add a global uncaughtException handler to Node.js services — A process.on('uncaughtException', handler) catches the fatal TypeError and keeps the process alive. This neutralizes the crash path entirely while you schedule the undici upgrade within the noisgate remediation SLA of 365 days.
  2. Allowlist outbound WebSocket destinations — If your application uses WebSocketStream, restrict the target URLs to a known-good allowlist via environment config or a network-layer egress policy. This eliminates the attacker-controlled-server prerequisite.
  3. Ensure process-manager auto-restart is configured — Verify that PM2, systemd Restart=always, or Kubernetes liveness probes are active for all Node.js services. This limits blast radius to a momentary restart even if the crash fires. No additional SLA — this should already be in place.
  4. Upgrade undici to ≥ 7.24.0 or pin Node.js to a patched release — The definitive fix. Schedule within the 365-day noisgate remediation SLA for MEDIUM findings. If you track Node.js LTS releases, confirm the bundled undici version includes the WebSocketStream close-handling patch.
What doesn't work
  • WAF / reverse proxy in front of the Node.js app — The vulnerability is in the *outbound* WebSocket client, not in inbound request handling. A WAF inspecting inbound traffic has no visibility into the app's outbound WebSocket connections.
  • Rate limiting inbound requests — The crash is triggered by the remote *server's* behavior (unclean close), not by the volume or shape of inbound client requests to your app.
  • Disabling WebSocket compression (permessage-deflate) — This mitigates CVE-2026-2229 and CVE-2026-1526 but not this bug, which is in the close-handling lifecycle regardless of compression settings.
06 · Verification

Crowdsourced verification payload.

Run on any host with Node.js installed to check whether the bundled or installed undici version is vulnerable. No special privileges required. Example: bash check_undici.sh

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_undici.sh — Detect CVE-2026-85014 (undici WebSocketStream unclean close DoS)
# Run on any host with node installed. No privileges required.
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

# Try to get undici version from node's built-in
UNDICI_VER=$(node -e "try { const v = process.versions.undici || require('undici/package.json').version; console.log(v); } catch(e) { console.log('NONE'); }" 2>/dev/null || echo "NONE")

if [ "$UNDICI_VER" = "NONE" ]; then
  echo "UNKNOWN — undici not found (not bundled or not installed)"
  exit 2
fi

echo "Detected undici version: $UNDICI_VER"

# Parse major and minor
MAJOR=$(echo "$UNDICI_VER" | cut -d. -f1)
MINOR=$(echo "$UNDICI_VER" | cut -d. -f2)

# 6.x is not affected (no WebSocketStream)
if [ "$MAJOR" -le 6 ]; then
  echo "PATCHED — undici $UNDICI_VER (6.x branch does not include WebSocketStream)"
  exit 0
fi

# 7.x: fixed in 7.24.0+
if [ "$MAJOR" -eq 7 ]; then
  if [ "$MINOR" -ge 24 ]; then
    echo "PATCHED — undici $UNDICI_VER (>= 7.24.0)"
    exit 0
  else
    echo "VULNERABLE — undici $UNDICI_VER (7.x < 7.24.0)"
    exit 1
  fi
fi

# 8.x+: assume patched (fix forward-ported)
if [ "$MAJOR" -ge 8 ]; then
  echo "PATCHED — undici $UNDICI_VER (8.x includes close-handling fix)"
  exit 0
fi

echo "UNKNOWN — unexpected version $UNDICI_VER"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
This is a MEDIUM finding with a noisgate reassessed score of 4.5 — no emergency response required. There is no active exploitation evidence and no KEV listing, so standard SLA timelines apply. Since MEDIUM carries no mitigation SLA, go straight to the 365-day noisgate remediation SLA: schedule your undici upgrade to ≥ 7.24.0 (or the corresponding Node.js release) within your next quarterly patching cycle. In the interim, verify that all Node.js services have process-manager auto-restart configured and consider adding a global uncaughtException handler as a zero-cost safety net. If you operate any services that use WebSocketStream to connect to *untrusted* external endpoints (aggregators, federation relays, proxy services), prioritize those for earlier patching — but for the vast majority of your 10,000-host fleet, this CVE will not be reachable.

Sources

  1. undici GitHub issue #4732 — WebSocketStream internal error on connection failure
  2. GHSA-v9p9-hfj2-hcw8 — Unhandled Exception in WebSocket Client (CVE-2026-2229)
  3. Snyk — Uncaught Exception in undici (CVE-2026-1528)
  4. GHSA-vxpw-j846-p89q — WebSocket fragment count bypass DoS (CVE-2026-12151)
  5. undici releases — GitHub
  6. NVD — CVE-2026-12151 Detail
  7. undici npm package
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.