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
•Technically reviewed by Anupam Mediratta•Published August 29, 2026•Reviewed 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

medium

path-to-regexp 0.1.12 DoS: Catastrophic Backtracking on Malformed URL

path-to-regexp version 0.1.12 contains a regular expression engine vulnerability where maliciously crafted URL parameters trigger exponential backtracking, causing CPU exhaustion and service unavailability. Upgrading to version 0.1.13 eliminates the vulnerable pattern from the parsing logic.

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.