In June 2024, maintainers of the popular Node.js ws WebSocket library disclosed CVE-2024-37890, a denial-of-service (DoS) vulnerability that allows a remote, unauthenticated attacker to crash a Node.js process handling WebSocket upgrade requests by sending a single specially crafted HTTP request. Because ws sits underneath a huge share of the Node.js real-time ecosystem — directly and as a transitive dependency of frameworks and libraries built on top of it — the practical blast radius of this bug extended far beyond applications that import ws explicitly. Any server accepting untrusted WebSocket connections on a vulnerable version was exposed to a full-process crash, not merely a failed connection, making this a textbook example of why supply-chain visibility into transitive dependencies matters as much as visibility into direct ones.
What the vulnerability does
ws is one of the most widely used WebSocket client/server implementations for Node.js, providing the protocol-handling layer that many higher-level real-time libraries build on. The flaw tracked as CVE-2024-37890 (published under GitHub Security Advisory GHSA-3h5v-q93c-6h6q) lives in how ws parses request headers during the WebSocket handshake, specifically around extension negotiation (Sec-WebSocket-Extensions). An attacker who sends a request engineered to exceed the header-count handling the library expects can trigger an unhandled exception during parsing. Because that exception occurs outside normal per-connection error handling, it isn't isolated to the offending socket — it can bring down the entire Node.js process serving the WebSocket endpoint.
That distinction is what makes this a genuine denial-of-service issue rather than a minor edge-case bug: a single malicious request, requiring no authentication and no user interaction, can take an entire service offline for every connected user, not just the attacker's own session. There is no data disclosure or tampering risk associated with the flaw — confidentiality and integrity are not affected — but availability impact is severe and trivially remote-triggerable, which is exactly the profile that earns a DoS bug a high severity rating even without any data-exposure component.
Affected versions and components
The vulnerability affects the ws package across all four release lines the maintainers were actively supporting at the time:
ws8.0.0 through 8.17.0 — fixed in 8.17.1ws7.0.0 through 7.5.9 — fixed in 7.5.10ws6.0.0 through 6.2.2 — fixed in 6.2.3ws5.0.0 through 5.2.3 — fixed in 5.2.4
Because ws is a foundational dependency, the practical exposure surface is much larger than "projects that require('ws') directly." It ships as a transitive dependency inside a long list of frameworks, tooling, and real-time libraries in the Node.js ecosystem, including build tools, development servers, and Socket.IO-adjacent packages that rely on ws under the hood. Teams that never consciously chose to depend on ws were frequently running vulnerable versions of it anyway, pulled in two or three layers deep by something else in package-lock.json or yarn.lock. This is the recurring pattern with foundational infrastructure packages: the direct dependency count understates true exposure by a wide margin, and a simple npm ls ws at the top level will miss instances buried in nested node_modules trees with pinned or lagging transitive versions.
Severity, exploitability, and exploitation status
GitHub's advisory rates CVE-2024-37890 as High severity, consistent with a CVSS v3.1 base score of 7.5 for the underlying vector: network-exploitable, low attack complexity, no privileges required, no user interaction required, and a high impact to availability with no impact to confidentiality or integrity. In plain terms, that scoring reflects exactly the risk described above — trivial to trigger remotely, easy to automate, and capable of taking down an entire process rather than degrading a single request.
As of this writing, CVE-2024-37890 does not appear in CISA's Known Exploited Vulnerabilities (KEV) catalog, and there is no confirmed evidence of widespread active exploitation in the wild. That should not be read as "low urgency," however. DoS bugs in widely deployed, low-friction-to-trigger network libraries are exactly the kind of vulnerability that gets weaponized quickly and quietly by scanners and opportunistic attackers once proof-of-concept exploitation details circulate, precisely because they require no credentials, no social engineering, and no complex chaining — just a single crafted request against any reachable WebSocket endpoint. Absence from KEV today is a snapshot, not a guarantee, and it shouldn't be the basis for deprioritizing the fix.
Timeline
- Discovery and private disclosure: The issue was identified and reported to the
wsmaintainers through GitHub's coordinated disclosure process ahead of public release. - June 2024: The maintainers published patched releases across all four affected major version lines (5.2.4, 6.2.3, 7.5.10, and 8.17.1) simultaneously with the public advisory, GHSA-3h5v-q93c-6h6q, and the corresponding CVE-2024-37890 assignment.
- Following weeks: Downstream projects and frameworks that bundle
wsas a transitive dependency began issuing their own dependency bumps, and dependency-scanning tools and package managers surfaced advisories to consumers runningnpm audit,yarn audit, or equivalent supply-chain tooling.
The relatively fast, coordinated patch release across every supported major version is a good example of responsible maintenance — but it also means the vulnerability window for slow-moving consumers has been open for well over a year at this point, with no excuse remaining for organizations that haven't verified their exposure.
Remediation steps
- Identify every instance of
wsin your dependency graph, not just the top-level one. Runnpm ls wsoryarn why wsacross all workspaces and services, and don't stop at the first match — transitive copies at different versions frequently coexist in the samenode_modulestree. - Upgrade to the fixed version matching your major line: 5.2.4, 6.2.3, 7.5.10, or 8.17.1 (or later). If you're pinned to an older major line for compatibility reasons, confirm the specific patched version for that line rather than jumping to the latest major, which may introduce breaking changes you haven't budgeted time to test.
- Force resolution for stubborn transitive copies. If a framework or tool you depend on hasn't bumped its own
wspin yet, use your package manager's override mechanism (overridesin npm,resolutionsin Yarn, orpnpm.overrides) to force the patched version until the upstream dependency catches up. - Re-run your lockfile and rebuild. A version bump in
package.jsonalone doesn't help if your lockfile still resolves to the vulnerable version — regenerate the lockfile and confirm the resolved version innode_modulesbefore shipping. - Add regression coverage for handshake failures. If your service accepts WebSocket connections from untrusted clients, add basic fuzz or malformed-request testing to your CI so a similar parsing edge case doesn't reach production undetected next time.
- Verify in runtime, not just in the manifest. Confirm the deployed artifact — container image, serverless bundle, or build output — actually contains the patched file, since build caches and vendored dependency snapshots can drift from what's declared in source control.
How Safeguard Helps
CVE-2024-37890 is a clean illustration of the gap that pure manifest-scanning tools routinely miss: the vulnerable package usually isn't the one a team consciously chose, it's several layers down in the dependency tree, quietly pulled in by something else. Safeguard is built specifically to close that gap across the software supply chain.
Safeguard continuously inventories every direct and transitive dependency across your repositories and build artifacts — not just what's declared at the top of package.json — so a vulnerability like this one in ws is surfaced everywhere it actually exists, including nested copies at different resolved versions within the same tree. When an advisory like GHSA-3h5v-q93c-6h6q is published, Safeguard correlates it against your real, deployed dependency graph, prioritizes remediation using severity and exploitability signals rather than raw CVE counts, and flags exactly which services, containers, or build pipelines are exposed. That lets security and engineering teams answer "are we affected, and where?" in minutes instead of coordinating a manual, repo-by-repo grep across dozens of services.
Because the highest-risk pattern with library-level DoS bugs is a transitive dependency lagging behind its upstream fix, Safeguard also tracks whether the fix has actually propagated into your build output — not just whether a lockfile entry looks correct — closing the loop between "patched in source" and "patched in production." For supply-chain risks like CVE-2024-37890, that continuous, artifact-level verification is the difference between a fix that looks complete on paper and one that's actually eliminated the exposure.