< Back to Feed // 08 JUL 2026 // Maliq Barnard

CVE-2026-59224 — Open WebUI Terminal Proxy Forwards Spoofable Identity

Open WebUI's terminal proxy passes X-User-Id to upstream services as a raw header with no cryptographic binding. If anything else can reach the upstream, it can impersonate any user.

CVE: CVE-2026-59224 GHSA: GHSA-j657-m4c4-24jq CVSS: 8.0 / 10 Severity: High CWE: CWE-290, CWE-287 Affected: Open WebUI < 0.10.0 Patched: Open WebUI ≥ 0.10.0 Credit: Maliq Barnard (smoke-wolf)


The terminal proxy thing

Open WebUI has this feature where you can shell into containers from the browser. Pretty standard stuff for AI dev platforms at this point. I was reading through the proxy code (terminals.py) and found this on line 108:

headers = {'X-User-Id': user.id}

So when you open a terminal session, Open WebUI authenticates you on its side, then tells the upstream terminal server who you are by sticking your user ID in a header. That's the whole mechanism. There's no signature on it, no JWT wrapping it, nothing that lets the other end verify it actually came from a real session.

This turned out to be two attack surfaces, not one.

HTTP path — unsigned identity forwarding

The bearer auth branch sends a shared API key — same key for every user — plus that X-User-Id header. The only thing differentiating user A from user B is the header value. Anyone who can reach the upstream terminal server directly can set it to whatever they want. The upstream has no way to distinguish a legitimate forwarded identity from a forged one.

The session and OAuth branches are slightly better because they forward actual tokens the upstream could theoretically validate. But the unsigned header still rides along on all of them.

WebSocket path — session_id query injection

The WebSocket proxy has a separate problem. The session_id parameter gets appended to the upstream URL without URL-encoding or validation. So you can inject ? and & characters through session_id to override the user_id parameter that gets appended after it.

That's a more direct attack path. You don't need to reach the upstream separately — you can do it right through Open WebUI's own WebSocket proxy by crafting the session ID.

What you actually get

Access to another user's terminal containers and live PTY sessions. If the terminal server scopes sessions by user_id — which is the whole point of forwarding it — then spoofing the ID gives you their sessions. Combined with a known session ID from shared chats or a predictable ID scheme, that's full impersonation at the terminal layer.

For an AI platform where people are running model training, data pipelines, and code execution through these terminals, that's not a theoretical concern.

What I filed

Static evidence on the HTTP path. I didn't build a full exploit chain with a fake upstream and spoofed sessions — the code path was clear enough. Here's the identity claim, here's why it's not verifiable, here's what breaks.

The maintainers accepted it and found the WebSocket vector during their own review. GitHub assigned CVE-2026-59224 on July 7. Fix shipped in 0.10.0.

Fix

Replace the raw header with a signed JWT — {uid, iat, aud} signed with a per-upstream key. URL-encode the session_id before appending it to the WebSocket URL. Both fixed in 0.10.0.

Timeline

Date Event
June 2026 Found HTTP path during source audit
June 2026 Filed via GitHub Security Advisory
July 7, 2026 CVE-2026-59224 assigned (CVSS 8.0)
July 2026 Patched in Open WebUI 0.10.0

Third CVE overall. First two were completely different — unsigned browser updates (CVE-2026-41431) and a path traversal in an OSINT tool (CVE-2026-42866). This one's a trust boundary issue in the most popular open-source AI frontend. Different class of bug but honestly the root cause is always some version of the same thing, code trusting input it never verified.

VIEWS: 6

Suggested Intelligence

Analyst Notes