Introduction
In this project's dependency tree, a critical vulnerability was lurking inside websocket-driver version 0.7.4—a widely-used Node.js library responsible for parsing and generating WebSocket protocol frames. Flagged by Trivy as CVE-2026-54466, this flaw sits at the intersection of untrusted network input and protocol-level parsing, meaning any application accepting WebSocket connections through this library was potentially exposed.
What makes this particularly dangerous is the context in which websocket-driver operates. The application already has concerns around plugin execution privileges (as noted in unchain_runtime/server/route_memory.py, where plugins execute with full Node.js runtime access to the filesystem, network, and child processes). A WebSocket-level vulnerability in this environment doesn't just risk connection hijacking—it could serve as an entry point that, combined with the unsandboxed plugin runtime, gives an attacker a path from a crafted WebSocket frame to full system access.
The fix is deceptively simple—a version bump from 0.7.4 to 0.7.5—but the implications of not applying it are severe. Let's dig into exactly what went wrong and how it was resolved.
The Vulnerability Explained
What is websocket-driver?
websocket-driver is a low-level Node.js library that implements the WebSocket protocol (RFC 6455). It handles the byte-level parsing of WebSocket frames: reading opcodes, masking keys, payload lengths, and reassembling fragmented messages. It's used by higher-level libraries like faye-websocket and often appears deep in dependency trees of frameworks like Webpack Dev Server, Socket.IO, and others.
What went wrong in version 0.7.4?
CVE-2026-54466 describes a flaw in how websocket-driver 0.7.4 parses incoming WebSocket frames from untrusted clients. The library's pluggable I/O architecture means it accepts raw byte streams and interprets them according to the WebSocket protocol. In the vulnerable version, certain malformed or specially crafted frame sequences were not properly validated, allowing an attacker to:
- Inject malicious frames that the server interprets as legitimate messages
- Manipulate the frame-parsing state machine to desynchronize the server's view of the connection from the client's
- Potentially smuggle data past application-level validation that trusts the WebSocket layer
A concrete attack scenario
Consider the application's architecture: it uses WebSocket connections (served through the dependency chain that includes websocket-driver) and runs plugins with full Node.js runtime privileges (as documented in unchain_runtime/server/route_memory.py). Here's how an attacker could chain these issues:
- An attacker connects to the application's WebSocket endpoint
- They send a specially crafted sequence of WebSocket frames that exploits the parsing flaw in
websocket-driver0.7.4 - The injected frame contains a command or message that the application's plugin system interprets as a legitimate instruction
- Because plugins execute without sandboxing—with full access to
fs,net, andchild_process—the injected command triggers file system access, network exfiltration, or arbitrary command execution
Even without the plugin escalation path, the WebSocket frame injection alone is critical: it breaks the fundamental trust boundary that the WebSocket protocol is supposed to enforce between client and server.
Why was this hard to catch?
The vulnerable code lives in package-lock.json as a transitive dependency. The project doesn't directly depend on websocket-driver—it's pulled in by another package in the dependency tree. This means:
- It doesn't appear in the project's
package.jsondependencies - Standard code review wouldn't catch it
- Only an SCA (Software Composition Analysis) scanner examining the full resolved dependency tree would flag it
Here's what the vulnerable lockfile entry looked like:
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
"license": "Apache-2.0",
"dependencies": {
"http-parser-js": ">=0.5.1",
Version 0.7.4 is the vulnerable version. The integrity hash confirms this is the exact artifact with the flaw.
The Fix
The fix involves two coordinated changes across package.json and package-lock.json:
1. Adding an npm override in package.json
Because websocket-driver is a transitive dependency (not directly listed in dependencies or devDependencies), a simple version bump in package.json wouldn't work. Instead, the fix uses npm's overrides mechanism to force the entire dependency tree to resolve to the patched version:
Before:
"overrides": {
"shell-quote": "1.9.0"
}
After:
"overrides": {
"shell-quote": "1.9.0",
"websocket-driver": "0.7.5"
}
The overrides field in package.json tells npm: "No matter which package depends on websocket-driver, resolve it to version 0.7.5." This is the correct approach for patching transitive dependencies without restructuring the entire dependency tree.
Note that shell-quote was already being overridden for a previous security fix—this pattern of accumulating overrides for transitive dependency vulnerabilities is common in mature projects.
2. Updating package-lock.json
The lockfile was regenerated to reflect the new resolved version:
Before:
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
After:
"node_modules/websocket-driver": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz",
"integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==",
Both the version number and integrity hash changed, confirming that a genuinely different (patched) artifact is now being installed.
Why both files must change
package.json: Declares the override intent—without this, a futurenpm installcould resolve back to0.7.4package-lock.json: Records the actual resolved version—without this update, existing CI/CD pipelines usingnpm ci(which installs from the lockfile) would continue installing the vulnerable version
Behavior preservation
The websocket-driver 0.7.5 release is a patch-level semver bump. It tightens input validation on WebSocket frame parsing but does not change the public API. Valid WebSocket frames are handled identically; only malformed/malicious frames are now properly rejected. This means the fix has zero impact on legitimate application behavior.
Prevention & Best Practices
1. Automate dependency scanning in CI/CD
Integrate tools like Trivy, Snyk, or npm audit into your CI pipeline so that every pull request is checked against the latest CVE databases:
# Example GitHub Actions step
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
2. Use npm overrides for transitive dependency fixes
When a vulnerability exists in a transitive dependency, don't wait for the intermediate package to update. Use overrides (npm 8.3+) or resolutions (Yarn) to force the patched version:
{
"overrides": {
"vulnerable-package": ">=patched.version"
}
}
3. Audit your WebSocket attack surface
If your application accepts WebSocket connections, ensure that:
- Frame parsing libraries are up to date
- Application-level message validation doesn't rely solely on the WebSocket layer for integrity
- Rate limiting and connection throttling are in place
4. Address the plugin sandboxing gap
The broader context of this fix highlights a compounding risk: unsandboxed plugins (unchain_runtime/server/route_memory.py) combined with a network-level vulnerability creates a critical escalation path. Consider implementing:
- A manifest-based permission system for plugins
- Node.js --experimental-permission flags or vm2/isolated-vm for plugin isolation
- Principle of least privilege for plugin filesystem and network access
5. Reference standards
- CWE-94: Improper Control of Generation of Code ('Code Injection')
- CWE-1395: Dependency on Vulnerable Third-Party Component
- OWASP A06:2021: Vulnerable and Outdated Components
Key Takeaways
- Transitive dependencies are a hidden attack surface:
websocket-driverwasn't listed inpackage.jsonbut was still exploitable—lockfile scanning is essential. - npm overrides are the correct mechanism for transitive dependency patches: Directly editing
package-lock.jsonwithout the corresponding override inpackage.jsonwill not persist across installs. - WebSocket frame parsing flaws are protocol-level vulnerabilities: They bypass application-layer validation because the application trusts the WebSocket layer to deliver well-formed messages.
- Vulnerability chaining multiplies risk: CVE-2026-54466 alone is critical, but combined with the unsandboxed plugin execution in
unchain_runtime/server/route_memory.py, it becomes a potential remote code execution vector. - Patch-level semver bumps (0.7.4 → 0.7.5) can carry critical security fixes: Don't ignore minor version changes in security-sensitive libraries.
How Orbis AppSec Detected This
- Source: Incoming WebSocket frame data from untrusted network clients, parsed by the
websocket-driverlibrary in the application's dependency tree - Sink: The WebSocket frame-parsing logic in
websocket-driver0.7.4, which improperly validated frame sequences, allowing injection into the application's message handling pipeline - Missing control: No input validation or integrity check on malformed WebSocket frame sequences at the library level; no npm override forcing a patched version of the transitive dependency
- CWE: CWE-94 (Improper Control of Generation of Code) and CWE-1395 (Dependency on Vulnerable Third-Party Component)
- Fix: Added an npm override pinning
websocket-driverto version 0.7.5 inpackage.jsonand regeneratedpackage-lock.jsonto resolve the patched artifact
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
CVE-2026-54466 is a textbook example of why dependency management is a first-class security concern. A single transitive dependency—websocket-driver 0.7.4—introduced a critical WebSocket frame injection vulnerability that could be exploited by any network-connected attacker. The fix was a targeted, two-file change: an npm override in package.json and an updated package-lock.json, upgrading to the patched 0.7.5 release.
For teams running Node.js applications with WebSocket endpoints, this is a reminder to scan your full dependency tree (not just direct dependencies), use overrides to patch transitive vulnerabilities immediately, and consider the compounding risks when vulnerable network-facing code interacts with privileged runtime environments. Security is only as strong as its weakest transitive dependency.
References
- CWE-94: Improper Control of Generation of Code ('Code Injection')
- CWE-1395: Dependency on Vulnerable Third-Party Component
- OWASP Vulnerable and Outdated Components
- npm Overrides Documentation
- websocket-driver npm package
- Semgrep Rules for Dependency Vulnerabilities
- fix: upgrade websocket-driver to 0.7.5 (CVE-2026-54466)