GitHub Advisoryadvisory · PyPI

GHSA-8jjp-r2w2-4v22 Open WebUI: Low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption

HIGH Published 2026-05-14 Modified 2026-05-15 Official page ↗
Aliases
CVE-2026-45399
Ecosystem
PyPI
Packages
open-webui
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H
Weaknesses
CWE-862
Reviewed
2026-05-14

Affected packages

• PyPI open-webui: < 0.9.0 → fixed in 0.9.0

Description

Summary Any authenticated user with low privileges can enumerate active background tasks across the system and stop tasks belonging to other users via the GET /api/tasks and POST /api/tasks/stop/{task_id} methods. This allows a casual user to disrupt system-wide chat usage by continuously canceling other users' active tasks. This is a real authorization vulnerability affecting integrity and usability in multi-user deployments. Details Open WebUI exposes `GET /api/tasks` and `POST /api/tasks/stop/{task_id}` to any verified user. These endpoints operate on a global task namespace and accept raw `task_id` values without checking whether the task belongs to the current caller. As a result, a normal authenticated user can enumerate active global task IDs and stop tasks belonging to other users. Root cause: 1. Route authorization is too weak. In `backend/open_webui/main.py`, both endpoints only require `get_verified_user`: ```python @app.post('/api/tasks/stop/{task_id}') async def stop_task_endpoint(request: Request, task_id: str, user=Depends(get_verified_user)): result = await stop_task(request.app.state.redis, task_id) @app.get('/api/tasks') async def list_tasks_endpoint(request: Request, user=Depends(get_verified_user)): return {'tasks': await list_tasks(request.app.state.redis)} ``` `get_verified_user` accepts both `user` and `admin` roles in `backend/open_webui/utils/auth.py`. 2. The helper operates on a global namespace. In `backend/open_webui/tasks.py`, task listing is global: ```python async def list_tasks(redis): if redis: return await redis_list_tasks(redis) return list(tasks.keys()) ``` In `backend/open_webui/tasks.py`, task stopping is by raw `task_id`: ```python async def stop_task(redis, task_id: str): if redis: item_id = await redis.hget(REDIS_TASKS_KEY, task_id) await redis_send_command(redis, {'action': 'stop', 'task_id': task_id}) await redis_cleanup_task(redis, task_id, item_id or None) ``` There is no owner check, no `user_id` check, and no mapping from `task_id` back to the current caller before stop or cleanup. This also appears unintended because the codebase already has a scoped route, `GET /api/tasks/chat/{chat_id}`, which checks whether the chat belongs to the current user before returning task IDs. Relevant code references: • `backend/open_webui/main.py:1975` • `backend/open_webui/main.py:1984` • `backend/open_webui/main.py:1989` • `backend/open_webui/tasks.py:127` • `backend/open_webui/tasks.py:145` • `backend/open_webui/utils/auth.py:415` Suggested remediation: • Store task ownership metadata such as `user_id` and `chat_id`, then enforce owner-only access for non-admin users • Suggested implementation locations: • `backend/open_webui/main.py`: add authentication checks for `/api/tasks` and `/api/tasks/stop/{task_id}` • `backend/open_webui/tasks.py`: add support for storing/querying task ownership metadata such as `user_id` and `chat_id`, and support owner-scoped listing/stopping PoC Preconditions: • Default `main` branch deployment • Authentication enabled • Two normal user accounts, or any multi-user deployment where the attacker has one authenticated non-admin account • At least one task actively running for another user This does not require any weakened security settings. PoC objective: 1. Show that a non-admin user can see global active task IDs that are not their own 2. Show that the same user can stop another user's active task Reproduction steps: Step 1. Victim starts a long-running task Using the UI, User A starts a long response generation or another background task and leaves it running. Expected security model: User B should not be able to see or control User A's task. Step 2. Attacker enumerates global task IDs Using User B's authenticated token: ```bash curl -i -H "Authorization: Bearer " http:///api/tasks ``` Expected result: • only User B's own task IDs should be returned, or • the endpoint should be admin-only Actual result: the response returns the global active task list. Example response shape: ```json {"tasks":["",""]} ``` This exposes task IDs belonging to other users. Step 3. Attacker stops a foreign task Pick a task ID that belongs to User A and send: ```bash curl -i -X POST -H "Authorization: Bearer " http:///api/tasks/stop/ ``` Expected result: • `403 Forbidden`, or • `404 Not Found` for non-owned tasks, or • admin-only access Actual result: the server accepts the request and attempts to stop the foreign task. Example response shape: ```json {"status":true,"message":"Task stopped."} ``` Step 4. Observe boundary violation User A's running task is interrupted or disappears from the active task set even though User B does not own it. What actions become possible that should not be possible: • enumerate globally active task IDs across users • cancel another user's in-progress generation or background work • repeat this for every returned task ID, causing broad cross-user disruption Copy-paste PoC summary: 1. Enumerate all active tasks as a normal non-admin user ```bash curl -s -H "Authorization: Bearer " http:///api/tasks ``` 2. Stop a task that does not belong to that user ```bash curl -s -X POST -H "Authorization: Bearer " http:///api/tasks/stop/ ``` Impact Type of vulnerability: broken object-level authorization affecting a global runtime control-plane endpoint. Who is impacted: • all users in a multi-user Open WebUI deployment • any user currently running a background task, especially chat generation tasks • administrators indirectly, because normal users can disrupt system-wide usage without admin privileges Direct impact: • cross-user task ID disclosure • cross-user task cancellation Practical impact: • interruption of long-running chat responses • interruption of background indexing or ingestion tasks associated with shared runtime jobs • one ordinary authenticated low-privilege user can continuously poll `/api/tasks` and immediately cancel every newly created active task • with a simple loop or script, this becomes a practical persistent denial-of-service against chat usage for all users on the instance • in a multi-user deployment, normal users may be unable to complete any chat generation while the attacker continues polling and cancelling tasks Why severity is meaningful: • privileges required: low, only an authenticated non-admin account • scope: cross-user • impact class: integrity and availability • exploitation complexity: low once logged in This is not full account takeover or privilege escalation, but it enables platform-wide operational disruption from a low-privilege account. In practice, sustained exploitation can make chat functionality effectively unusable for other users on the system. Resolution Fixed in commit e7ff4768f (#23454, "Add ownership checks to global task endpoints"), first released in v0.9.0 (Apr 2026). The fix takes a simpler approach than per-task ownership tracking, which would have required a schema change to attribute every task to a `user_id`: • `GET /api/tasks` and `POST /api/tasks/stop/{task_id}` are restricted to admin-only via `Depends(get_admin_user)`. Cross-user enumeration and termination are no longer reachable from a non-admin account. • A new scoped `POST /api/tasks/chat/{chat_id}/stop` endpoint covers the legitimate non-admin use case (a user stopping their own in-progress generation), reusing the same chat-ownership check the existing `GET /api/tasks/chat/{chat_id}` already enforces. CVE-2025-63681 was a prior disclosure of the same authorization gap against v0.6.33; the fix in v0.9.0…

Related

Alias · CVE (1)

  • CVE-2026-45399 Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. vulnerability

Weakness · CWE (1)

  • CWE-862 Missing Authorization weakness

References