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-server → sockjs → websocket-driver, or faye-websocket → websocket-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:
- Read a raw HTTP request and validate the upgrade handshake —
Sec-WebSocket-Key,Sec-WebSocket-Version,Sec-WebSocket-Extensions. - Compute and emit the handshake response.
- Parse the framing protocol byte by byte: opcodes,
FIN/RSVbits, 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:
- The attacker sends a single TCP connection carrying a crafted HTTP upgrade request to
/ws. The headers are constructed so the fronting proxy andhttp-parser-js@0.5.3disagree 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. - The proxy sees one benign upgrade request and forwards the whole byte stream.
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.- Alternatively, the attacker skips the handshake abuse and targets the frame parser: an upgrade that negotiates a malformed
Sec-WebSocket-Extensionsvalue, followed by frames with inconsistent length fields, drives the0.7.4state 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-jsis 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 intonode_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