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

Frequently Asked Questions

What is a vulnerable dependency vulnerability?

It is a flaw you inherit rather than write. Your own code may be perfectly safe, but a package in your dependency tree — here `websocket-driver@0.7.4`, pulled in transitively by dev-server and SockJS tooling — contains a known, published defect. Attackers scan for the vulnerable version, not for your code, so the version string in your lockfile is the actual attack surface.

How do you prevent vulnerable dependencies in Node.js?

Commit your lockfile, run a scanner (Trivy, `bun audit`, `npm audit`, Dependabot) in CI on every pull request, and use `overrides`/`resolutions`/catalog entries to force a single patched version of transitive packages. Prefer libraries that use ranges (`>=0.5.1`) rather than exact pins for their own dependencies, because exact pins block security patches from propagating.

What CWE is a vulnerable dependency?

CWE-1395, "Dependency on Vulnerable Third-Party Component" (closely related to CWE-1104, "Use of Unmaintained Third Party Components"). The downstream impact of the specific CVE may map to other CWEs — for example CWE-444 for HTTP request smuggling in the `http-parser-js` version that 0.7.4 froze, or CWE-330 for `form-data`'s unsafe random boundary in CVE-2025-7783.

Is running `bun audit` locally enough to prevent vulnerable dependencies?

No. A local audit is a point-in-time snapshot, and new advisories are published after you install. You need the check enforced in CI so an unpatched lockfile cannot merge, plus overrides that stop a nested `package.json` from silently reintroducing `websocket-driver@0.7.4` on the next `bun install`.

Can static analysis detect vulnerable dependencies?

Yes — software composition analysis tools such as Trivy read `bun.lock` directly and match resolved versions against advisory databases, which is exactly how CVE-2026-54466 was found here. Traditional code-level static analysis is complementary: it can tell you whether the vulnerable API is actually reachable from your code, which advisory matching alone cannot.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #10809

Related Articles

high

How Dependabot Missing Cooldown Periods Enable Supply Chain Attacks and How to Fix It

A critical security vulnerability in `.github/dependabot.yml` was exposing a Node.js library to supply chain attacks by automatically updating to newly published packages without a safety delay. By adding a 7-day cooldown period to each package ecosystem configuration, the project now protects against malicious or unstable package versions that could affect downstream consumers.

high

How Exponential-Time Complexity Causes Denial of Service in brace-expansion and How to Fix It

A critical vulnerability in brace-expansion versions 1.1.13 and earlier allowed attackers to cause denial of service through crafted brace pattern inputs. The fix upgrades to patched versions 1.1.16, 2.1.2, and 5.0.7, eliminating the exponential-time complexity that made exploitation possible.

high

How unrestricted file upload via extension-only validation happens in Deno/JavaScript and how to fix it

The review image upload handler in this Deno-based app trusted the client-supplied filename extension to decide whether a file was a "safe" image, without ever inspecting the actual file bytes. The fix adds magic-byte signature verification for PNG, JPEG, GIF, and WEBP formats before the file is written to disk, closing the door on disguised executables and malicious payloads.

high

How Missing Dependabot Cooldown Periods Enable Supply Chain Attacks in CI/CD Pipelines and How to Fix Them

We fixed a high-severity supply chain security gap in `.github/dependabot.yml` where missing cooldown periods allowed immediate adoption of newly published packages. The fix adds `cooldown: default-days: 7` to all package ecosystems, creating a critical security buffer against typosquatting and malicious dependency attacks.

high

How Dependabot Missing Cooldown Vulnerability Happens in GitHub Actions and How to Fix It

Dependabot configurations without cooldown periods can automatically propose updates from newly published packages within hours—potentially including malicious or unstable versions. This vulnerability in `.github/dependabot.yml` was fixed by adding a `cooldown` block with `default-days: 7` to delay updates and allow time for community vetting.

critical

How Arbitrary Code Execution Via Command Injection happens in Node.js and how to fix it

A critical arbitrary code execution flaw in the `shell-quote` npm package (CVE-2026-9277) allowed attackers to break out of shell quoting using unescaped Unicode line terminator characters, turning ordinary command-line arguments into injected shell commands. The fix locks `shell-quote` to the patched `1.8.4` release via a `resolutions` override in `package.json`/`yarn.lock`, closing off a transitive dependency path that could otherwise pull in a vulnerable version.