CVE-2026-59216: Open WebUI: Cross-user code-interpreter and tool execution via unvalidated Socket.IO event-caller session_id
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 (geteventcall) delivers execute:python / execute:tool events to a client-supplied sessionid 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/openwebui/socket/main.py — geteventcall() / eventcaller - backend/openwebui/main.py — chat-completion metadata (sessionid taken from the request body)
Root cause
The event-caller routes to a caller-controlled session id with no ownership check:
python backend/openwebui/socket/main.py — geteventcall() async def eventcaller(eventdata): sessionid = requestinfo['sessionid'] if sessionid not in SESSIONPOOL: # only checks the session is connected return {'error': 'Client session disconnected.'} return await sio.call('events', {...}, to=sessionid, ...) # delivered to that sid
sessionid originates from the request body and is never validated against the authenticated user:
python backend/openwebui/main.py metadata = { 'userid': user.id, # server-derived (trustworthy) 'sessionid': formdata.pop('sessionid', None), # client-controlled ... }
SESSIONPOOL[sessionid] is the user record of whoever owns that socket. Because the caller checks only membership (in SESSIONPOOL), a request carrying another user's sessionid 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 geteventcall. - The victim's live sessionid is disclosed to any read-access participant of a shared note via ydoc:document:join. - POST /api/v1/chat/completions requires only getverifieduser (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
geteventcall must verify the target session belongs to the requesting user before delivering, not merely that it is connected:
python session = SESSIONPOOL.get(sessionid) if session is None or session.get('id') != requestinfo.get('userid'): return {'error': 'Client session disconnected.'}
userid in the request metadata is server-derived from the authenticated user, so it is trustworthy. Restricting ydoc:document:join so it does not disclose other participants' socket ids is recommended as defence-in-depth.
Affected / Patched
- Affected: < 0.10.0 (last affected release 0.9.6) - Patched: v0.10.0. geteventcall now verifies the target session belongs to the requesting user before delivering (session is None or session.get('id') != requestinfo.get('userid')), using the server-derived userid from the request metadata. The recommended ydoc:document:join sid-disclosure restriction is defence-in-depth and independent of this fix; the ownership check closes the cross-user delivery regardless of whether the victim's sid is known.
Other sources
Open WebUI is an extensible, feature-rich, and user-friendly self-hosted AI platform. Prior to 0.10.0, geteventcall delivered execute:python and execute:tool Socket.IO events to a client-supplied sessionid after checking only that the session was connected, allowing authenticated users who learned another socket ID through ydoc:document:join to run code interpreter Python or tools in that user session. This issue is fixed in version 0.10.0.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/open-webuito a version that resolves this vulnerability.Fixed in 0.10.0 - Upgrade
Upgrade
Open WebUIto a version that resolves this vulnerability.Fixed in 0.10.0 - Configuration
Update get_event_call/__event_caller__ to verify the target Socket.IO session belongs to the authenticated requester using the server-derived request metadata user_id, rather than only checking session connectivity in SESSION_POOL.
Socket.IO event-caller (backend/open_webui/socket/main.py get_event_call / __event_caller__) session_id ownership validation = Verify target session belongs to requesting user before delivering events (if session is None or session.get('id') != request_info.get('user_id'), do not deliver; return {'error': 'Client session disconnected.'}) - Configuration
Apply defence-in-depth by restricting ydoc:document:join so read-access participants cannot learn other users’ socket ids needed to target cross-user session delivery.
Shared notes collaboration (ydoc:document:join) socket id disclosure to read-access participants = Restrict ydoc:document:join so it does not disclose other participants' live socket ids
Event History
Frequently Asked Questions
What is the severity of CVE-2026-59216?
CVE-2026-59216 has a severity rating of 7.7, classified as high.
How do I fix CVE-2026-59216?
To fix CVE-2026-59216, upgrade Open WebUI to version 0.10.0 or later.
What is the impact of CVE-2026-59216?
CVE-2026-59216 allows authenticated users to execute arbitrary code through unvalidated Socket.IO events.
Who is affected by CVE-2026-59216?
Users of Open WebUI versions prior to 0.10.0 are affected by CVE-2026-59216.
What type of vulnerability is CVE-2026-59216?
CVE-2026-59216 is categorized as a code injection and information leakage vulnerability.