Back to Blog
critical SEVERITY5 min read

How a vulnerable websocket-driver dependency happens in Node.js lockfiles and how to fix it

A Trivy scan flagged `websocket-driver@0.7.4` in this repository's `bun.lock` as affected by CVE-2026-54466, a critical issue in a WebSocket protocol handler that parses untrusted HTTP upgrade requests and frame data. The fix upgrades the package to `0.7.5` and adds an explicit `websocket-driver` entry to the lockfile's override block so every transitive consumer — webpack-dev-server, sockjs, faye-websocket — resolves to the patched build instead of the pinned vulnerable one.

O
By Orbis AppSec
Published August 31, 2026Reviewed August 31, 2026

Answer Summary

This is a vulnerable third-party dependency issue (CWE-1395) in a Node.js/Bun project: `websocket-driver@0.7.4`, a WebSocket protocol handler that parses untrusted handshake headers and frames, is affected by CVE-2026-54466 (critical). Making things worse, 0.7.4 hard-pinned `http-parser-js` to exactly `0.5.3`, freezing a transitive HTTP-parsing dependency that cannot be patched independently. The fix is to upgrade to `websocket-driver@0.7.5` — which relaxes those pins to `http-parser-js: >=0.5.1`, `safe-buffer: >=5.1.0`, `websocket-extensions: >=0.1.1` — and to add `"websocket-driver": "0.7.5"` to the override/catalog block in `bun.lock` and `package.json` so no dependency can pull the old version back in.

Vulnerability at a Glance

cweCWE-1395
fixUpgrade to `websocket-driver@0.7.5` and add an explicit `"websocket-driver": "0.7.5"` override so the whole dependency tree dedupes onto the patched version
riskUntrusted WebSocket handshake and frame data is parsed by an unpatched protocol handler, with a hard-pinned HTTP parser that cannot receive security fixes
languageJavaScript / Node.js (Bun workspace)
root cause`bun.lock` resolved `websocket-driver@0.7.4` transitively with no override, and 0.7.4 pins `http-parser-js` to exactly `0.5.3`
vulnerabilityUse of a vulnerable third-party dependency (`websocket-driver@0.7.4`, CVE-2026-54466)

Summary

A Trivy scan flagged websocket-driver@0.7.4 in this repository's bun.lock as affected by CVE-2026-54466, rated critical. websocket-driver is the low-level WebSocket protocol handler that parses attacker-supplied HTTP upgrade headers and binary frames, so an unpatched version sits directly on an untrusted input path. The fix upgrades the package to 0.7.5 and adds an explicit websocket-driver entry to the lockfile's override block, so every transitive consumer in the workspace dedupes onto the patched build.

Introduction

The bun.lock file in this monorepo is a 9,000-line map of exactly which byte-for-byte version of every package gets loaded at runtime. Nobody wrote websocket-driver into a package.json here — it arrived transitively, the way it usually does: webpack-dev-serversockjswebsocket-driver, or faye-websocketwebsocket-driver. It was resolved, locked, and forgotten.

That is precisely the problem. Line 8898 of the lockfile read:

"websocket-driver": ["websocket-driver@0.7.4", "", {
  "dependencies": {
    "http-parser-js": "0.5.3",
    "safe-buffer": "5.2.1",
    "websocket-extensions": "0.1.4"
  }
}, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="],

Two things are worth staring at. First, websocket-driver@0.7.4 is the version named in CVE-2026-54466. Second — and this is the part developers usually miss — look at "http-parser-js": "0.5.3". That is not a range. It is an exact pin, hard-coded inside a third-party package's manifest. No amount of bun update in this repository can move that transitive dependency forward while websocket-driver@0.7.4 is in the tree. The vulnerable version pinned another package into place with it.

If you maintain a Node.js service that terminates WebSockets, runs a dev server, or embeds SockJS, this pattern is almost certainly in your lockfile too.

The Vulnerability Explained

What websocket-driver actually does

websocket-driver is described by its own authors as "a WebSocket protocol handler with pluggable I/O." It is the state machine underneath faye-websocket, sockjs, and webpack-dev-server's HMR channel. Its job is to:

  1. Read a raw HTTP request and validate the upgrade handshake — Sec-WebSocket-Key, Sec-WebSocket-Version, Sec-WebSocket-Extensions.
  2. Compute and emit the handshake response.
  3. Parse the framing protocol byte by byte: opcodes, FIN/RSV bits, payload length fields (7-bit, 16-bit, and 64-bit variants), masking keys, and continuation frames.

Every single one of those inputs comes from the network before any authentication has happened. A WebSocket handshake is, by definition, pre-auth traffic. That is why an advisory in this package carries a critical rating even when the library is three levels deep in a dependency tree: the parser runs before your code gets a say.

The frozen http-parser-js pin

The most concrete, inspectable defect in the old entry is the dependency pinning. Compare the resolved manifests:

// BEFORE — websocket-driver@0.7.4
"dependencies": {
  "http-parser-js": "0.5.3",       // exact pin — cannot be patched
  "safe-buffer": "5.2.1",          // exact pin
  "websocket-extensions": "0.1.4"  // exact pin
}

http-parser-js is the pure-JavaScript HTTP parser that websocket-driver uses to read the upgrade request in lib/websocket/driver/server.js. Versions of http-parser-js below 0.5.8 are affected by CVE-2022-32210, an HTTP request smuggling issue (CWE-444, "Inconsistent Interpretation of HTTP Requests") caused by lenient header parsing that a fronting proxy interprets differently. Because 0.7.4 pinned 0.5.3 exactly, that fix could never reach this application, no matter how aggressively the team updated its own direct dependencies.

This is the compounding effect of stale dependencies: one outdated package can act as a version lock on a whole subtree of security patches.

Attack scenario for this application

Suppose a service in this workspace exposes a SockJS or faye-websocket endpoint behind a reverse proxy or CDN that enforces authentication on /api/* but passes /ws through untouched:

  1. The attacker sends a single TCP connection carrying a crafted HTTP upgrade request to /ws. The headers are constructed so the fronting proxy and http-parser-js@0.5.3 disagree about where the first request ends — a header value containing bytes the proxy treats as terminators but the pinned parser folds into the previous header, or vice versa.
  2. The proxy sees one benign upgrade request and forwards the whole byte stream.
  3. websocket-driver's server-side handshake code, backed by the vulnerable parser, sees two requests. The second one — never inspected by the proxy — is smuggled directly to the origin, carrying whatever path and headers the attacker chose, including a forged trusted identity header the proxy would normally strip.
  4. Alternatively, the attacker skips the handshake abuse and targets the frame parser: an upgrade that negotiates a malformed Sec-WebSocket-Extensions value, followed by frames with inconsistent length fields, drives the 0.7.4 state machine down an unpatched path.

Note the honest caveat in the PR's own assessment: "Present in dependency tree, not confirmed reachable." Whether a given service in this monorepo actually terminates untrusted WebSocket traffic through this driver — versus only loading it inside webpack-dev-server on a developer laptop — determines real exploitability. That nuance is worth documenting per-service. It is not a reason to leave a critical, pre-auth protocol parser on a known-vulnerable version in a committed lockfile.

The Fix

The change touches exactly two files and does not modify a single line of application code. That is the point: this is a supply-chain fix, and the correct remediation is a version pin, not a code rewrite.

1. Bump the resolved version in bun.lock

-    "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": "0.5.3", "safe-buffer": "5.2.1", "websocket-extensions": "0.1.4" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="],
+    "websocket-driver": ["websocket-driver@0.7.5", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA=="],

Two distinct security wins are packed into this one line:

  • The integrity hash changed (sha512-b17K…sha512-ZL2+…), which is the cryptographic proof that a different, patched tarball will be installed. Bun verifies this hash on install, so the fix cannot be silently downgraded by a compromised registry mirror.
  • The exact pins became ranges: http-parser-js: "0.5.3"">=0.5.1", safe-buffer: "5.2.1"">=5.1.0", websocket-extensions: "0.1.4"">=0.1.1". The version lock described above is gone. http-parser-js is now free to resolve to a release that includes the CVE-2022-32210 fix, and the resolver can dedupe it with whatever version the rest of the tree already uses instead of forcing a second copy into node_modules.

One follow-up is worth doing by hand: because the loosened range only takes effect on resolution, confirm that the http-parser-js entry elsewhere in bun.lock actually landed on 0.5.8 or newer after install. A range that permits a patched version is not the same as a lockfile that records one.

Also note that websocket-extensions stays at 0.1.4 in the lockfile — which is correct. 0.1.4 is the patched release for CVE-2020-7662, the ReDoS in

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #10809

Related Articles

critical

deleteNestedProperty Prototype Pollution via Dot-Notation Path

The `deleteNestedProperty` function in propertyUtils.ts allowed attackers to manipulate JavaScript object prototypes by passing specially crafted dot-notation paths like `__proto__.polluted`. A fix now blocks dangerous keys before processing, preventing prototype pollution attacks that could affect all objects in the application.

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.