GHSA-gv8f-wpm2-m5wr: @siteboon/claude-code-ui Vulnerable to Unauthenticated RCE via WebSocket Shell Injection
Security Advisory: Insecure Default JWT Secret + WebSocket Auth Bypass Enables Unauthenticated RCE via Shell InjectionDownload: [cve_claudecodeui_submission_v2.zip](https://github.com/user-attachments/files/25686652/cve_claudecodeui_submission_v2.zip) Submission Info| Field | Value |
|-------|-------|
| **Package** | `@siteboon/claude-code-ui` |
| **Ecosystem** | npm |
| **Affected versions** | `<= 1.24.0` (latest) |
| **Severity** | Critical |
| **CVSS Score** | 9.8 |
| **CVSS Vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` |
| **CWE** | CWE-1188, CWE-287, CWE-78 |
| **Reported** | 2026-03-02 |
| **Researcher** | Ethan-Yang (OPCIA) |SummaryThree chained vulnerabilities allow **unauthenticated remote code execution** on any
claudecodeui instance running with default configuration. No account, credentials, or
prior access is required.The root cause of RCE is **OS command injection (CWE-78)** in the WebSocket shell
handler. Authentication is bypassed by combining an insecure default JWT secret
**(CWE-1188)** with a WebSocket authentication function that skips database user
validation **(CWE-287)**.Vulnerability Details1. Insecure Default JWT Secret — `CWE-1188`**File**: `server/middleware/auth.js`, line 6The server uses an environment variable for `JWT_SECRET`, but falls back to a
well-known default value when the variable is not set. Critically, `JWT_SECRET` is
**not included in `.env.example`**, so the majority of users deploy without setting it,
leaving the fallback value in effect.Since this default string is published verbatim in the public source code, any attacker
can use it to sign arbitrary JWT tokens.2. WebSocket Authentication Skips Database Validation — `CWE-287`**File**: `server/middleware/auth.js`, lines 82–108`authenticateWebSocket()` only verifies the JWT **signature**. It does **not** check
whether the `userId` in the payload actually exists in the database — unlike
`authenticateToken()` which is used for REST endpoints and does perform this check:A forged token with a non-existent `userId` passes WebSocket authentication,
bypassing access control entirely.3. OS Command Injection via WebSocket Shell — `CWE-78`**File**: `server/index.js`, line 1179Both `projectPath` and `initialCommand` are taken directly from the WebSocket message
payload and interpolated into a bash command string without any sanitization,
enabling arbitrary OS command execution.A secondary injection vector exists at line 1257 via unsanitized `sessionId`:Proof of Concept**Requirements**: Node.js, `jsonwebtoken`, `ws`**Actual output observed during testing:**Secondary vector — `projectPath` double-quote escape injectionAdditional Findings| CWE | Location | Description |
|-----|----------|-------------|
| CWE-306 | `server/routes/auth.js:22` | `/api/auth/register` requires no authentication — first caller becomes admin |
| CWE-942 | `server/index.js:325` | `cors()` with no options sets `Access-Control-Allow-Origin: *` |
| CWE-613 | `server/middleware/auth.js:70` | `generateToken()` sets no `expiresIn` — tokens never expire |ImpactAny claudecodeui instance accessible over the network where `JWT_SECRET` is not
explicitly configured (the default case, as it is absent from `.env.example`) is
vulnerable to:**Full OS command execution** as the server process user**File system read/write** access**Credential theft** (SSH keys, `.env` files, API keys stored on the host)**Lateral movement** within the host networkThe attack requires **zero authentication** and succeeds immediately after
default installation.RemediationFix 1 — Enforce explicit JWT_SECRET; remove insecure defaultAlso add `JWT_SECRET=` to `.env.example` with a clear instruction to set a strong random value.Fix 2 — Add DB user existence check in WebSocket authenticationFix 3 — Replace shell string interpolation with spawn argument arrayFix 4 — Additional hardeningAdd `expiresIn: '24h'` to `generateToken()`Restrict CORS to specific trusted originsRate-limit and restrict `/api/auth/register` to localhost on initial setupTimeline| Date | Event |
|------|-------|
| 2026-03-02 | Vulnerabilities discovered and verified via PoC |
| 2026-03-02 | Private advisory submitted to maintainer |
| 2026-06-01 | Public disclosure (90-day deadline) |Researcher**Ethan-Yang** — OPCIA
CVSS v4.0: 8.7