CVE-2026-70490: Open WebUI: Unapproved accounts can open terminal sessions via a WebSocket auth path missing the role check
Open WebUI 0.8.8 up to 0.10.x lets accounts that are not approved, or were deactivated, open interactive terminal sessions over WebSocket. The WebSocket route skips the role check the HTTP terminal routes enforce. It matters only where a terminal server is configured. Upgrade to 0.11.0.
Published Aug 4, 2026 · Analysis Oct 25, 2026
What an attacker can do
WebSocket handshakes cannot use FastAPI dependencies, so _resolve_authenticated_connection in backend/open_webui/routers/terminals.py re-implemented authentication for the /{server_id}/api/terminals/{session_id} route. It checked the JWT and that the user row exists, but dropped the role check that get_verified_user applies on every HTTP terminal route. An account with role pending therefore gets a shell session that the HTTP endpoints refuse.
The attacker needs a valid, unexpired JWT for a pending account and the terminal server id. Both are available to someone who registered while approval is pending. They are also available to a user an admin deactivated: deactivation sets the role to pending without revoking the token, which lasts four weeks by default. A terminal server must be configured (off by default) and its grants must cover the account, either public read (principal_id: "*") or a group the account still belongs to.
The result is interactive shell, file browsing and terminal-backed tooling for as long as the token lives. Admins see access revoked over HTTP while the WebSocket keeps working. Terminal grants themselves still hold: an account with no grant is refused.
Who is affected
Open WebUI >= 0.8.8, < 0.11.0 with at least one terminal server configured and grants that are public or reach a group the account still belongs to. Deployments with no terminal server, or with admin-only grants, are not affected. Check the version:
pip show open-webuiopen-webui
- Ecosystem
- PyPI
- Affected
- >= 0.8.8, < 0.11.0
- Fixed in
- 0.11.0
- Check
pip show open-webui
How to fix it
Upgrade to 0.11.0:
pip install --upgrade open-webui==0.11.0Pull request 27537 merges token decoding, revocation checking, user lookup and the role check into one get_verified_user_by_token helper. Both the terminal WebSocket route and the Socket.IO handshake use it, and the role set is shared with the HTTP gate. No configuration change is needed. Until then, narrowing terminal grants to admins removes the exposure, per the stated preconditions.
How to tell if you were hit
List accounts with role pending, especially ones that were deactivated recently, and check terminal server logs and Open WebUI logs for WebSocket sessions on /{server_id}/api/terminals/{session_id} opened by them. Look inside terminal environments for shell history and files created by those users. After upgrading, deactivated users' still-valid tokens lose live access, per the 0.11.0 release notes.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
The terminal WebSocket route authenticates its own first-message JWT instead of going through the HTTP dependency chain, and never applies the role check that get_verified_user enforces on every HTTP terminal route. An account whose role is pending, meaning registered but not approved, or approved and later deactivated back to pending, can therefore open an interactive terminal session that the HTTP terminal endpoints would refuse. The missing control is the verified-user role gate, not the terminal access grants, which are evaluated correctly.
Preconditions
At least one terminal server must be configured, which is off by default, and its access grants must cover the account: either public read (principal_id: "*") or a group the account still belongs to. The attacker needs a valid, unexpired JWT for a pending account and the terminal server id. Both are obtainable by an account that registered while approvals are pending, or by one that held access and was deactivated, since deactivation sets the role to pending without revoking the token, which lasts four weeks by default. Deployments with no terminal server configured, or whose terminal grants are admin-only, are not affected.
Impact
A deployment loses the account-approval boundary for terminal access. An unapproved or deactivated account gets interactive shell access, file browsing and terminal-backed tooling in the terminal environment, for as long as its token remains valid. Because the HTTP terminal routes correctly reject the same account, the two planes disagree, so an administrator who deactivates a user sees access revoked over HTTP while the WebSocket keeps working. The terminal access grants themselves are not bypassed: an account with no grant is still refused, so this only widens access to terminals already shared broadly or with a group the account remains in.
Fix
Fixed in v0.11.0 by https://github.com/open-webui/open-webui/pull/27537. Token decoding, revocation checking, user lookup and the role check are consolidated into a single get_verified_user_by_token helper, and both the terminal WebSocket route and the Socket.IO handshake now go through it. The role set lives in one constant shared with the HTTP gate so the two cannot drift apart again. Upgrading fully resolves the issue; no configuration change is required.
Root cause
Affected component: backend/open_webui/routers/terminals.py, the _resolve_authenticated_connection helper backing the /{server_id}/api/terminals/{session_id} WebSocket route. Affected setup: every build from v0.8.8 onward, since the route was introduced there.
WebSocket handshakes cannot use FastAPI dependencies, so this route reimplemented authentication inline. The reimplementation reproduced the parts that are visible in the token, that it decodes and that the user row exists, and silently dropped the part that lives in the database row, the role check. Authorization then ran on two independent code paths with no shared definition of what an authenticated user is, and only one of them was updated when the role gate was introduced.
Credits
Reported by @rexpository.
Credited to rexpository, Classic298.
Questions
- Does CVE-2026-70490 bypass terminal access grants?
No. An account with no grant is still refused. It widens access only to terminals already shared publicly or with a group the unapproved account belongs to.
- Why does a deactivated user keep access?
Deactivation sets the role to
pendingbut does not revoke the JWT, which is valid for four weeks by default. The HTTP routes reject it, but the WebSocket route did not check the role.- Am I affected without a terminal server?
No. The advisory says deployments with no terminal server configured are not affected. Terminal servers are off by default.
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
