Back to Blog
critical SEVERITY7 min read

How Unsandboxed Plugin Execution Happens in Node.js and How to Fix It

A critical vulnerability (CVE-2026-54466) was discovered in the `websocket-driver` dependency (version 0.7.4), which handles WebSocket protocol framing and I/O. The fix upgrades the package to version 0.7.5 via an npm override in `package.json` and an updated lockfile, closing a WebSocket frame-parsing flaw that could allow attackers to inject or manipulate WebSocket traffic. This dependency-level fix is essential because the vulnerable library sits in the application's dependency tree and proce

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

Answer Summary

CVE-2026-54466 is a critical WebSocket frame-parsing vulnerability in the Node.js `websocket-driver` library (version 0.7.4) that could allow attackers to inject malicious frames or hijack WebSocket connections. It is related to CWE-94 (Improper Control of Generation of Code) and broader input-validation weaknesses. The fix is to upgrade `websocket-driver` to version 0.7.5 by adding an npm override in `package.json` and regenerating `package-lock.json`.

Vulnerability at a Glance

cweCWE-94 / CWE-1395
fixUpgrade websocket-driver from 0.7.4 to 0.7.5 via npm override
riskAttackers can inject or manipulate WebSocket frames, potentially hijacking connections or executing arbitrary actions
languageJavaScript (Node.js)
root causewebsocket-driver 0.7.4 improperly handles untrusted WebSocket frame data during parsing
vulnerabilityVulnerable third-party dependency (WebSocket frame injection)

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:

  1. Inject malicious frames that the server interprets as legitimate messages
  2. Manipulate the frame-parsing state machine to desynchronize the server's view of the connection from the client's
  3. 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:

  1. An attacker connects to the application's WebSocket endpoint
  2. They send a specially crafted sequence of WebSocket frames that exploits the parsing flaw in websocket-driver 0.7.4
  3. The injected frame contains a command or message that the application's plugin system interprets as a legitimate instruction
  4. Because plugins execute without sandboxing—with full access to fs, net, and child_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.json dependencies
  • 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 future npm install could resolve back to 0.7.4
  • package-lock.json: Records the actual resolved version—without this update, existing CI/CD pipelines using npm 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.

Key Takeaways

  • Transitive dependencies are a hidden attack surface: websocket-driver wasn't listed in package.json but was still exploitable—lockfile scanning is essential.
  • npm overrides are the correct mechanism for transitive dependency patches: Directly editing package-lock.json without the corresponding override in package.json will 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-driver library in the application's dependency tree
  • Sink: The WebSocket frame-parsing logic in websocket-driver 0.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-driver to version 0.7.5 in package.json and regenerated package-lock.json to 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.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #238

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.