CVE-2026-59219: Open WebUI: Realtime endpoints accept Redis-revoked JWTs after signout/backchannel logout
With Redis configured, Open WebUI rejects revoked JWTs over HTTP but still accepts them on Socket.IO and terminal websocket connections. A token revoked by sign-out or OIDC back-channel logout keeps working for realtime access. Versions 0.9.0 up to 0.10.0 are affected. Upgrade to 0.10.0.
Published Jul 24, 2026 · Analysis Oct 25, 2026
What an attacker can do
HTTP auth in get_current_user calls is_valid_token, which checks the Redis keys for a revoked jti and a per-user revoked_at. The realtime paths call decode_token() only, which checks signature and expiry. That covers Socket.IO connect, user-join, join-channels and join-note in socket/main.py, and the terminal websocket first-message auth in routers/terminals.py.
So a stolen token survives the usual remedy. After the victim signs out, or the identity provider sends back-channel logout, REST calls return 401, but a new Socket.IO connection with the same token still authenticates. The attacker can enter SESSION_POOL as the victim, join their user, channel and note rooms, read realtime channel messages, note updates and presence, act in collaboration as them, and pass terminal websocket auth when terminal servers are configured.
REST data and state-changing REST endpoints stay protected. The attacker needs a valid but revoked JWT, and a deployment with Redis. Without Redis, sign-out does not invalidate JWTs by design, so this bug adds nothing there.
Who is affected
open-webui from 0.9.0 up to but not including 0.10.0, and only when Redis is configured for revocation. The reporter reproduced it on 0.9.6 and main.
pip show open-webuiIf you do not run Redis, tokens are not revocable at all on these versions, which is a separate design limit.
open-webui
- Ecosystem
- PyPI
- Affected
- >= 0.9.0, < 0.10.0
- Fixed in
- 0.10.0
- Check
pip show open-webui
How to fix it
Upgrade to open-webui 0.10.0:
pip install --upgrade open-webui==0.10.0The revocation logic now lives in a shared helper, is_token_revoked, covering per-token jti and per-user revoked_at. It runs on Socket.IO connect, user-join, join-channels and join-note, and on the terminal websocket first-message auth, using the main app Redis. HTTP behaviour is unchanged. The release notes say revoked or expired sessions are rejected on real-time and terminal connections.
If a token may have leaked, upgrade, then restart so open sockets reconnect, and rotate the signing secret if you need to invalidate everything.
How to tell if you were hit
Compare the Socket.IO connections and terminal websocket sessions in your logs against sign-out and back-channel logout times for the same user. A connect or user-join event authenticated after the user's sign-out, or from a new address, indicates a revoked token in use. Check Redis for the {prefix}:auth:token:{jti}:revoked and {prefix}:auth:user:{id}:revoked_at keys to see which tokens were revoked.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
With Redis configured, Open WebUI supports JWT revocation: POST /api/v1/auths/signout (per-token jti) and OIDC back-channel logout (per-user revoked_at) record revocations in Redis, and HTTP auth (get_current_user) rejects revoked tokens with 401. The realtime authentication surfaces do not perform this check: Socket.IO connect / user-join / join-channels / join-note and the terminal websocket first-message auth validate tokens with decode_token() only (signature + expiry). A JWT revoked by sign-out or back-channel logout therefore continues to authenticate new realtime connections, even though the same token is rejected on HTTP.
Affected component
backend/open_webui/socket/main.py— Socket.IOconnect,user-join,join-channels,join-notebackend/open_webui/routers/terminals.py— terminal websocket first-message authbackend/open_webui/utils/auth.py— the revocation check was applied to HTTP only
Root cause
HTTP auth enforces revocation:
# utils/auth.py — get_current_user
if data.get('jti') and not await is_valid_token(request, data):
raise HTTPException(status_code=401, detail='Invalid token')Realtime auth calls decode_token() only, which verifies signature + expiry but never consults the Redis revocation keys ({prefix}:auth:token:{jti}:revoked, {prefix}:auth:user:{id}:revoked_at):
# socket/main.py — connect / user-join / join-channels / join-note
data = decode_token(auth['token'])
# routers/terminals.py — _resolve_authenticated_connection
data = decode_token(token)Impact
A JWT revoked by user sign-out or OIDC back-channel logout still authenticates new realtime connections. A stolen token therefore retains realtime access after the victim signs out or the IdP performs back-channel logout — the very remediation for a compromised token. The token can populate SESSION_POOL as the victim, join their user/channel/note rooms (receiving realtime channel messages, collaborative-note updates and presence), drive socket-level collaboration as the victim, and pass terminal websocket authentication when terminal servers are configured. HTTP remains correctly protected (401), so REST data and state-changing REST endpoints are not reachable with the revoked token.
Proof of Concept
Reporter PoC on a Redis-backed deployment (v0.9.6 and main): after POST /api/v1/auths/signout, HTTP returns 401 for the token while a Socket.IO user-join with the same token still authenticates, and the terminal WS reaches terminal-server lookup rather than rejecting it as Invalid token.
Fix
Apply the revocation check on the realtime paths. The logic is factored into is_token_revoked(redis, decoded) (covering per-token jti and per-user revoked_at); the Socket.IO handlers and the terminal WS reject tokens that fail it, using the main app Redis where revocations are stored. HTTP is_valid_token delegates to the same helper, so HTTP behaviour is unchanged.
Affected / Patched
- Affected:
>= 0.9.0, < 0.10.0, and only when Redis is configured (without Redis, per-token revocation is not supported and sign-out does not invalidate JWTs by design). - Patched: v0.10.0. The revocation check (
is_valid_token, covering per-tokenjtiand per-userrevoked_at) is applied on Socket.IO connect / user-join / join-channels / join-note and the terminal websocket first-message auth, using the main app Redis where revocations are stored. HTTPis_valid_tokendelegates to the same logic, so HTTP behaviour is unchanged.
Credited to huslayer826, Classic298.
Questions
- Can the attacker use the revoked token on REST endpoints?
No. HTTP still returns 401 for it. The advisory says REST data and state-changing REST endpoints are not reachable. Only the realtime Socket.IO and terminal websocket surfaces accept it.
- Am I affected without Redis?
This specific bug is not. Without Redis, per-token revocation is not supported and sign-out does not invalidate JWTs by design.
- Which versions are affected by CVE-2026-59219?
0.9.0 up to but not including 0.10.0, with Redis configured.
References
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Open WebUI vulnerabilities
All Open WebUI entriesCVE-2026-87011
Open WebUI: Unauthenticated requests can stall the server via uncached OIDC fetches in back-channel logout
high7.5Sep 10, 2026CVE-2026-87012
Open WebUI: Any authenticated user can suppress calendar alerts instance-wide via a non-numeric alert value
medium4.3Sep 10, 2026CVE-2026-87013
Open WebUI: Any authenticated user can start a non-terminating request via a folder parent cycle
medium4.3Sep 10, 2026CVE-2026-87014
Open WebUI: Admin demoted through SSO role sync keeps read and write access to all users' notes
medium6.5Sep 10, 2026CVE-2026-87015
Open WebUI: A user's session cookies are sent to tool servers configured for bearer authentication
medium6.8Sep 10, 2026CVE-2026-87016
Open WebUI: Sign-in as another user via wildcard characters in the OAuth subject claim on SQLite
high8.1Sep 10, 2026
