{"id":"CVE-2026-45399","aliases":["GHSA-8jjp-r2w2-4v22","PYSEC-2026-2714"],"title":"Open WebUI: Low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption","summary":"Open WebUI: Low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption","severity":"high","cvss":7.1,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H","vendor":"open-webui","product":"open-webui","ecosystem":"pip","affected":["open-webui < 0.9.0"],"patched":["open-webui 0.9.0"],"published":"2026-05-14","updated":"2026-07-13","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-8jjp-r2w2-4v22","references":[{"url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-8jjp-r2w2-4v22"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-45399"},{"url":"https://github.com/open-webui/open-webui/pull/23454"},{"url":"https://github.com/open-webui/open-webui/commit/e7ff4768f8ffe1924b4576381c9e45e8a64350e4"},{"url":"https://github.com/open-webui/open-webui"},{"url":"https://github.com/open-webui/open-webui/releases/tag/v0.9.0"}],"tags":["osv","pip"],"epss":0.00392,"epssPercentile":0.30488,"ingestedAt":"2026-07-13T18:57:55.176Z","slug":"CVE-2026-45399","body":"## Overview\n\n### Summary\nAny 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.\n\n\n### Details\nOpen 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.\n\nAs a result, a normal authenticated user can enumerate active global task IDs and stop tasks belonging to other users.\n\nRoot cause:\n\n1. Route authorization is too weak.\n\nIn `backend/open_webui/main.py`, both endpoints only require `get_verified_user`:\n\n```python\n@app.post('/api/tasks/stop/{task_id}')\nasync def stop_task_endpoint(request: Request, task_id: str, user=Depends(get_verified_user)):\n    result = await stop_task(request.app.state.redis, task_id)\n\n@app.get('/api/tasks')\nasync def list_tasks_endpoint(request: Request, user=Depends(get_verified_user)):\n    return {'tasks': await list_tasks(request.app.state.redis)}\n```\n\n`get_verified_user` accepts both `user` and `admin` roles in `backend/open_webui/utils/auth.py`.\n\n2. The helper operates on a global namespace.\n\nIn `backend/open_webui/tasks.py`, task listing is global:\n\n```python\nasync def list_tasks(redis):\n    if redis:\n        return await redis_list_tasks(redis)\n    return list(tasks.keys())\n```\n\nIn `backend/open_webui/tasks.py`, task stopping is by raw `task_id`:\n\n```python\nasync def stop_task(redis, task_id: str):\n    if redis:\n        item_id = await redis.hget(REDIS_TASKS_KEY, task_id)\n        await redis_send_command(redis, {'action': 'stop', 'task_id': task_id})\n        await redis_cleanup_task(redis, task_id, item_id or None)\n```\n\nThere is no owner check, no `user_id` check, and no mapping from `task_id` back to the current caller before stop or cleanup.\n\nThis 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.\n\nRelevant code references:\n- `backend/open_webui/main.py:1975`\n- `backend/open_webui/main.py:1984`\n- `backend/open_webui/main.py:1989`\n- `backend/open_webui/tasks.py:127`\n- `backend/open_webui/tasks.py:145`\n- `backend/open_webui/utils/auth.py:415`\n\nSuggested remediation:\n- Store task ownership metadata such as `user_id` and `chat_id`, then enforce owner-only access for non-admin users\n- Suggested implementation locations:\n  - `backend/open_webui/main.py`: add authentication checks for `/api/tasks` and `/api/tasks/stop/{task_id}`\n  - `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\n\n\n\n### PoC\nPreconditions:\n\n- Default `main` branch deployment\n- Authentication enabled\n- Two normal user accounts, or any multi-user deployment where the attacker has one authenticated non-admin account\n- At least one task actively running for another user\n\nThis does not require any weakened security settings.\n\nPoC objective:\n\n1. Show that a non-admin user can see global active task IDs that are not their own\n2. Show that the same user can stop another user's active task\n\nReproduction steps:\n\n#### Step 1. Victim starts a long-running task\n\nUsing the UI, User A starts a long response generation or another background task and leaves it running.\n\nExpected security model:\nUser B should not be able to see or control User A's task.\n\n#### Step 2. Attacker enumerates global task IDs\n\nUsing User B's authenticated token:\n\n```bash\ncurl -i -H \"Authorization: Bearer <USER_B_TOKEN>\" http://<open-webui-host>/api/tasks\n```\n\nExpected result:\n\n- only User B's own task IDs should be returned, or\n- the endpoint should be admin-only\n\nActual result:\nthe response returns the global active task list.\n\nExample response shape:\n\n```json\n{\"tasks\":[\"<task-id-a>\",\"<task-id-b>\"]}\n```\n\nThis exposes task IDs belonging to other users.\n\n#### Step 3. Attacker stops a foreign task\n\nPick a task ID that belongs to User A and send:\n\n```bash\ncurl -i -X POST -H \"Authorization: Bearer <USER_B_TOKEN>\" http://<open-webui-host>/api/tasks/stop/<FOREIGN_TASK_ID>\n```\n\nExpected result:\n\n- `403 Forbidden`, or\n- `404 Not Found` for non-owned tasks, or\n- admin-only access\n\nActual result:\nthe server accepts the request and attempts to stop the foreign task.\n\nExample response shape:\n\n```json\n{\"status\":true,\"message\":\"Task <FOREIGN_TASK_ID> stopped.\"}\n```\n\n#### Step 4. Observe boundary violation\n\nUser A's running task is interrupted or disappears from the active task set even though User B does not own it.\n\nWhat actions become possible that should not be possible:\n\n- enumerate globally active task IDs across users\n- cancel another user's in-progress generation or background work\n- repeat this for every returned task ID, causing broad cross-user disruption\n\nCopy-paste PoC summary:\n\n1. Enumerate all active tasks as a normal non-admin user\n\n```bash\ncurl -s -H \"Authorization: Bearer <USER_B_TOKEN>\" http://<open-webui-host>/api/tasks\n```\n\n2. Stop a task that does not belong to that user\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer <USER_B_TOKEN>\" http://<open-webui-host>/api/tasks/stop/<FOREIGN_TASK_ID>\n```\n\n### Impact\nType of vulnerability:\nbroken object-level authorization affecting a global runtime control-plane endpoint.\n\nWho is impacted:\n\n- all users in a multi-user Open WebUI deployment\n- any user currently running a background task, especially chat generation tasks\n- administrators indirectly, because normal users can disrupt system-wide usage without admin privileges\n\nDirect impact:\n\n- cross-user task ID disclosure\n- cross-user task cancellation\n\nPractical impact:\n\n- interruption of long-running chat responses\n- interruption of background indexing or ingestion tasks associated with shared runtime jobs\n- one ordinary authenticated low-privilege user can continuously poll `/api/tasks` and immediately cancel every newly created active task\n- with a simple loop or script, this becomes a practical persistent denial-of-service against chat usage for all users on the instance\n- in a multi-user deployment, normal users may be unable to complete any chat generation while the attacker continues polling and cancelling tasks\n\nWhy severity is meaningful:\n\n- privileges required: low, only an authenticated non-admin account\n- scope: cross-user\n- impact class: integrity and availability\n- exploitation complexity: low once logged in\n\nThis 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.\n\n## Resolution\n\nFixed in commit [e7ff4768f](https://github.com/open-webui/open-webui/commit/e7ff4768f8ffe1924b4576381c9e45e8a64350e4) ([#23454](https://github.com/open-webui/open-webui/pull/23454), \"Add ownership checks to global task endpoints\"), first released in **v0.9.0** (Apr 2026).\n\nThe 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`:\n\n- `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.\n- 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.\n\nCVE-2025-63681 was a prior disclosure of the same authorization gap against v0.6.33; the fix in v0.9.0 also resolves that.\n\nUsers on `>= 0.9.0` are not affected.\n\n## Affected packages\n\n- `open-webui < 0.9.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `open-webui 0.9.0`","depth":"twilight","depthScore":39,"depthScoreParts":{"impact":39.1,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}