Safeguard
Vulnerability Analysis

ws WebSocket library header DoS (CVE-2021-32640)

CVE-2021-32640 lets attackers stall Node.js WebSocket servers via a crafted header in the widely-used ws npm package. Here's the fix.

Nayan Dey
Security Researcher
7 min read

A specially crafted Sec-WebSocket-Extensions header is all it takes to bring a Node.js WebSocket server to its knees. CVE-2021-32640 affects ws, the ubiquitous WebSocket implementation for Node.js that ships as a direct or transitive dependency in thousands of npm packages — including socket.io, engine.io, and numerous testing and tooling frameworks. The flaw lives in how ws parses the extension-negotiation header used to set up the permessage-deflate compression extension: a maliciously constructed header value forces the parser into pathological, CPU-intensive behavior, allowing a remote, unauthenticated attacker to significantly degrade or stall a server's event loop with a single HTTP request during the WebSocket handshake. No authentication, no valid WebSocket session, and no user interaction are required — just a TCP connection and a crafted header.

Because ws sits underneath so much of the Node.js real-time ecosystem, the practical blast radius of this bug extends well past developers who imported ws directly. Any application, framework, or internal tool that pulls in a vulnerable ws version transitively inherits the exposure, which is exactly the kind of supply-chain-amplified risk that makes dependency-level vulnerabilities disproportionately dangerous compared to their CVSS score alone would suggest.

Affected Versions and Components

The vulnerability affects the ws npm package across multiple major version lines:

  • ws < 5.2.3 (5.x line)
  • ws < 6.2.2 (6.x line)
  • ws < 7.4.6 (7.x line)

The root cause is in the extension header parsing logic used to negotiate WebSocket extensions during the opening handshake, specifically the code path that handles permessage-deflate — the compression extension most ws deployments enable by default or make configurable. Servers that accept incoming WebSocket connections and process the Sec-WebSocket-Extensions header are exposed regardless of whether the application logic itself ever uses compression; the vulnerable parsing occurs before the extension is actually negotiated or activated.

Given ws's position in the npm dependency graph, affected components commonly include:

  • Real-time frameworks built on socket.io / engine.io (which bundle ws as their WebSocket engine)
  • Development tooling such as browser automation libraries, hot-reload dev servers, and headless browser drivers that use ws for control-plane communication
  • Any custom Node.js WebSocket server or gateway that imports ws directly

Teams that only scan their direct package.json dependencies frequently miss this exposure entirely, since ws is pulled in two, three, or four levels deep in many popular toolchains.

Severity and Exploitability Context

The National Vulnerability Database and the GitHub Security Advisory (GHSA-6fc8-4gx4-v693) score this issue as High severity, with a CVSS v3.1 base score of 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). The vector reflects a network-exploitable, low-complexity attack that requires no privileges or user interaction and produces a pure availability impact — no confidentiality or integrity loss, but a meaningful ability to degrade or deny service.

From an exploitation-likelihood standpoint, this CVE has historically carried a low-to-moderate EPSS (Exploit Prediction Scoring System) score, consistent with most single-request denial-of-service issues: it's straightforward to trigger once understood, but it produces no data exfiltration or remote code execution, which limits its attractiveness for large-scale automated exploitation compared to RCE-class bugs. It has not been added to CISA's Known Exploited Vulnerabilities (KEV) catalog, and no widespread in-the-wild exploitation campaigns tied to it have been publicly documented. That said, absence from KEV should not be read as absence of risk — DoS primitives against real-time infrastructure (trading platforms, chat systems, live dashboards, IoT control channels) can have outsized operational and reputational impact even without a headline-grabbing exploitation campaign, and the low barrier to triggering the bug means opportunistic scanning against internet-facing WebSocket endpoints is plausible.

Disclosure Timeline

  • Discovery and private disclosure: The issue was identified in the ws extension-negotiation parsing logic and reported through responsible disclosure channels to the package maintainers.
  • Coordinated fix development: The ws maintainers developed patches across all three actively maintained major version lines (5.x, 6.x, and 7.x) to harden the extension header parsing against the pathological input.
  • Public disclosure and patch release: Fixed releases — ws@7.4.6, ws@6.2.2, and ws@5.2.3 — were published to npm, followed shortly by the public GitHub Security Advisory (GHSA-6fc8-4gx4-v693) and MITRE's assignment of CVE-2021-32640.
  • Downstream propagation: In the weeks and months following disclosure, downstream projects bundling ws (notably socket.io and various dev-tooling packages) issued their own updates pinning or bumping to patched ws versions, though — as is common with deeply nested transitive dependencies — full ecosystem remediation lagged the original fix by a considerable margin, and vulnerable ws versions have continued to surface in dependency scans of legacy projects years after the patch was available.

Remediation Steps

  1. Identify exposure across your entire dependency tree, not just top-level packages. Run npm ls ws or yarn why ws in every Node.js service and internal tool to enumerate both direct and transitive installations, since ws is frequently nested several layers deep under frameworks like socket.io.

  2. Upgrade to a patched version appropriate to your major version line:

    • ws 5.x → upgrade to >=5.2.3
    • ws 6.x → upgrade to >=6.2.2
    • ws 7.x → upgrade to >=7.4.6 If your direct dependencies allow it, standardize on the current major/minor release rather than the minimum patched version.
  3. Force resolution for transitive dependencies that haven't yet bumped their own ws requirement. Use overrides (npm), resolutions (Yarn), or pnpm.overrides in package.json to pin a safe ws version across the whole dependency graph, then verify with a fresh npm ls ws that no vulnerable copies remain.

  4. Re-lock and rebuild after upgrading — regenerate package-lock.json / yarn.lock and rebuild any Docker images or deployment artifacts that bundle node_modules, since a stale lockfile or cached image layer can silently reintroduce the vulnerable version.

  5. Apply compensating controls where an immediate upgrade isn't possible. Restrict or cap header sizes at your reverse proxy or load balancer (e.g., limiting Sec-WebSocket-Extensions header length), disable permessage-deflate negotiation if your application doesn't require compression, and add resource-based alerting (event-loop lag, CPU spikes) on WebSocket-handling processes so an exploitation attempt is caught operationally even before the patch lands.

  6. Validate the fix with a targeted test, ideally in a staging environment, by confirming the patched server no longer exhibits abnormal CPU or latency behavior when presented with malformed extension headers, and re-run your software composition analysis (SCA) scan to confirm zero remaining instances of vulnerable ws versions across all services.

How Safeguard Helps

Vulnerabilities like CVE-2021-32640 are exactly where flat CVSS scores mislead prioritization — a 7.5 sitting four dependency layers deep, in a code path your application may never actually reach, competes for attention with hundreds of other findings unless you can tell the difference. Safeguard's reachability analysis traces whether the vulnerable ws extension-parsing function is actually invocable from your application's exposed WebSocket handshake logic, cutting through noise so teams fix what's genuinely exploitable first. Griffin AI, Safeguard's security reasoning engine, correlates the finding against your real dependency graph, deployment context, and any compensating controls already in place to produce a risk-adjusted priority rather than a generic severity label. Safeguard's SBOM generation and ingestion capabilities give you continuous visibility into every nested copy of ws across your services — including ones introduced by frameworks like socket.io that most point-in-time scans miss — so exposure doesn't resurface silently after the next dependency bump. And when remediation is confirmed safe, Safeguard can open an auto-fix pull request that bumps ws to a patched version and updates lockfiles and override rules across affected repos, turning a multi-repo remediation sprint into a review-and-merge action.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.