Skip to content
Open WebUIGHSA-74h3-cxq7-vc5q

Open WebUI: Cross-user code-interpreter and tool execution via unvalidated Socket.IO event-caller session_id

High7.7CVE-2026-59216 · Published Jul 24, 2026 · updated Aug 4, 2026

GitHub advisory

Affected versions

PackageAffectedFixed in
open-webui
PyPI
< 0.10.00.10.0
Details and references

## Summary An authenticated low-privilege user can execute arbitrary code-interpreter Python and tools inside **another** user's authenticated session. The Socket.IO event-caller (`get_event_call`) delivers `execute:python` / `execute:tool` events to a **client-supplied** `session_id` after only checking that the session is connected, never that it belongs to the requester. Combined with `ydoc:document:join`, which exposes the live socket ids of everyone in a shared note's collaboration room to any read-access participant, an attacker can target a victim's session and run attacker-chosen code/tools in the victim's browser context. When the victim is an administrator, that hijacked context reaches the admin-only Functions API, whose source is executed server-side, yielding remote code execution as the server process (root in the default container). ## Affected component - `backend/open_webui/socket/main.py` , `get_event_call()` / `__event_caller__` - `backend/open_webui/main.py` , chat-completion metadata (`session_id` taken from the request body) ## Root cause The event-caller routes to a caller-controlled session id with no ownership check: ```python # backend/open_webui/socket/main.py , get_event_call() async def __event_caller__(event_data): session_id = request_info['session_id'] if session_id not in SESSION_POOL: # only checks the session is connected return {'error': 'Client session disconnected.'} return await sio.call('events', {...}, to=session_id, ...) # delivered to that sid ``` `session_id` originates from the request body and is never validated against the authenticated user: ```python # backend/open_webui/main.py metadata = { 'user_id': user.id, # server-derived (trustworthy) 'session_id': form_data.pop('session_id', None), # client-controlled ... } ``` `SESSION_POOL[session_id]` is the user record of whoever owns that socket. Because the caller checks only membership (`in SESSION_POOL`), a request carrying another user's `session_id` causes `execute:python` / `execute:tool` to be delivered to that other user's browser. ## Reachability - `execute:python` / `execute:tool` are emitted from the code-interpreter and tool-call paths (`utils/middleware.py`, `tools/builtin.py`), all routed through `get_event_call`. - The victim's live `session_id` is disclosed to any read-access participant of a shared note via `ydoc:document:join`. - `POST /api/v1/chat/completions` requires only `get_verified_user` (the default user role). The attacker uses their own account and a model / Direct Connection they control to choose the payload. ## Impact - **Any victim:** arbitrary code-interpreter Python and tool execution in the victim's authenticated session , the attacker acts with the victim's identity and origin (full session/account compromise). - **Admin victim:** the hijacked admin context reaches `POST /api/v1/functions/create`, whose source is `exec()`'d server-side → remote code execution as the server process (root in the default container). The Functions API is intended administrator code-execution; the vulnerability here is the cross-user delivery that lets an attacker drive another user's session , including an admin's , into it. The primitive is a full session compromise even against non-admin victims. ## Proof of Concept The reporter's `exploit.py` reproduced on `ghcr.io/open-webui/open-webui:0.9.6` and a build of the `v0.9.6` tag, confirming blind server-side RCE out-of-band (callback returns `uid=0(root)`), using only a low-privilege `user` account that shared a note with an admin victim. Preconditions: code interpreter enabled; attacker shares a note with the victim; victim opens it while online; admin victim required for server RCE. ## Fix `get_event_call` must verify the target session belongs to the requesting user before delivering, not merely that it is connected: ```python session = SESSION_POOL.get(session_

CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N
Severity from
GitHub (reviewed advisory)
Weakness
CWE-200, CWE-639, CWE-862, CWE-94
Also known as
CVE-2026-59216, PYSEC-2026-3592

More Open WebUI advisories

All Open WebUI
DateAdvisory
Jul 23Open WebUI's API key endpoint restrictions bypassed via `x-api-key` header , full message processing on restricted endpoints
CVE-2026-45339Medium6.5fixed in 0.9.0
Jul 24Open WebUI: Stored web worker XSS via Pyodide
CVE-2026-59214High7.3fixed in 0.10.0
Jul 24Open WebUI: Account enumeration via observable login timing discrepancy
CVE-2026-59218Medium5.3fixed in 0.10.0
Jul 24Open WebUI: Scheduled automations continue after pending-user deactivation and stored model ACL revocation
CVE-2026-59226Low3.1fixed in 0.10.0
Jul 24Open WebUI: ReDoS in skill-mention regexes causes whole-instance DoS on default config
CVE-2026-59220Medium6.5fixed in 0.10.0
Jul 24Open WebUI: POST /api/v1/images/edit bypasses the global image-edit switch and the per-user image-generation permission
CVE-2026-59227Medium4.3fixed in 0.10.0

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.