Where
AND
-Infinity
0
Severity
7.1
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N

Summary

With Redis configured, Open WebUI supports JWT revocation: POST /api/v1/auths/signout (per-token jti) and OIDC back-channel logout (per-user revokedat) record revocations in Redis, and HTTP auth (getcurrentuser) 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 decodetoken() 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/openwebui/socket/main.py — Socket.IO connect, user-join, join-channels, join-note - backend/openwebui/routers/terminals.py — terminal websocket first-message auth - backend/openwebui/utils/auth.py — the revocation check was applied to HTTP only

Root cause

HTTP auth enforces revocation:

python utils/auth.py — getcurrentuser if data.get('jti') and not await isvalidtoken(request, data): raise HTTPException(statuscode=401, detail='Invalid token')

Realtime auth calls decodetoken() only, which verifies signature + expiry but never consults the Redis revocation keys ({prefix}:auth:token:{jti}:revoked, {prefix}:auth:user:{id}:revokedat):

python socket/main.py — connect / user-join / join-channels / join-note data = decodetoken(auth['token']) routers/terminals.py — resolveauthenticatedconnection data = decodetoken(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 SESSIONPOOL 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 istokenrevoked(redis, decoded) (covering per-token jti and per-user revokedat); the Socket.IO handlers and the terminal WS reject tokens that fail it, using the main app Redis where revocations are stored. HTTP isvalidtoken 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 (isvalidtoken, covering per-token jti and per-user revokedat) 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. HTTP isvalidtoken delegates to the same logic, so HTTP behaviour is unchanged.

1 / 2
Source: GitHub
First published (updated )
Severity
4.3
AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L

Title: Scheduled automations continue after pending-user deactivation and stored model ACL revocation

Summary

Open WebUI documents pending as a zero-access role used for new sign-ups and deactivated users, and normal HTTP routes enforce that with getverifieduser() (which rejects pending), while automation create/update/run routes additionally require the features.automations permission. Two paths missed that lifecycle gate, so a deactivated (pending) account could keep acting through the background automation scheduler:

1. Scheduler did not re-gate the owner. When a stored automation became due, executeautomation() rehydrated the owner with Users.getuserbyid(...) and re-entered the chat completion pipeline without re-checking that the owner was still user/admin or still held features.automations. A still-active automation therefore kept running after its owner was deactivated. 2. Model ACL only enforced for exact role user. checkmodelaccess() applied private-model grants only when user.role == "user", so a pending principal fell through a branch that denies a normal non-owner user.

Net effect: a deactivated account could continue scheduled chat generation through the background worker, consuming the operator's configured model-provider credentials and reaching a stored automation model ID that its current role/ACL state would no longer permit through normal routes.

Impact

A pending/deactivated account continues to execute due scheduled automations after its access has been revoked, consuming the operator's provider credentials, quota and shared capacity, and bypassing the private-model ACL for the automation's stored model ID. Exploitation requires a previously created active automation and a later transition to pending (deactivation or approval rollback), so it is bounded and not interactive. It does not grant unauthenticated access, account takeover, code execution, or cross-user data exfiltration.

Patched

In 0.10.0:

- executeautomation() aborts and records an error unless the rehydrated owner is still user or admin and (for non-admins) still holds features.automations, so a deactivated or de-permissioned owner's due automation no longer runs. - checkmodelaccess() enforces model ACLs for every non-admin role rather than only the exact role user, so a pending or otherwise unrecognised role no longer falls through.

Credits

@rexpository

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203