CVE-2026-45399: Open WebUI Low-privilege Authenticated Users Can Enumerate Vulnerability

HIGH
Advisory Identifier: GHSA-8jjp-r2w2-4v22
CVSS 7.1
CWE-862
Published
Advisory Summary

CVE-2026-45399 is a HIGH (CVSS 7.1) low-privilege authenticated users can enumerate vulnerability (CWE-862: Missing Authorization) affecting Open WebUI libraries in the PyPI ecosystem. The issue involves low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption. Remediation is available by upgrading affected packages to version 0.9.0.

CVE-2026-45399 at a Glance

CVE Identifier CVE-2026-45399
GHSA Identifier GHSA-8jjp-r2w2-4v22
Severity HIGH
CVSS v3.1 Base Score 7.1
CWE Classification CWE-862: Missing Authorization
Affected Product Open WebUI
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 7.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-45399

To remediate this vulnerability, upgrade all affected Open WebUI dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

open-webui fixed: 0.9.0
pip install open-webui>=0.9.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show open-webui

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-45399, inspect your installed packages using pip:

pip show open-webui

Analyze the terminal output to locate any version of Open WebUI in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.9.0), your application is affected.

Note: The pip show open-webui command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-862: Missing Authorization, where the product does not perform an authorization check when an actor attempts to access a resource or perform an action. In Open WebUI, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### 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 <USER_B_TOKEN>" http://<open-webui-host>/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":["<task-id-a>","<task-id-b>"]} ``` 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 <USER_B_TOKEN>" http://<open-webui-host>/api/tasks/stop/<FOREIGN_TASK_ID> ``` 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 <FOREIGN_TASK_ID> 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 <USER_B_TOKEN>" http://<open-webui-host>/api/tasks ``` 2. Stop a task that does not belong to that user ```bash curl -s -X POST -H "Authorization: Bearer <USER_B_TOKEN>" http://<open-webui-host>/api/tasks/stop/<FOREIGN_TASK_ID> ``` ### 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](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). 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 also resolves that. Users on `>= 0.9.0` are not affected.

CVE-2026-45399 Affected Open WebUI Versions

1 component(s)
Fixed Versions:
0.9.0
Product / Package Ecosystem Affected Versions Fixed Version
open-webui
PyPI
< 0.9.0
0.9.0

References

Frequently Asked Questions

What is CVE-2026-45399?
CVE-2026-45399 is a security vulnerability in Open WebUI involving Low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption under CWE-862: Missing Authorization.
Which Open WebUI versions are affected?
Affected versions include releases prior to 0.9.0 across affected packages: open-webui.
What version fixes CVE-2026-45399?
Upgrading to 0.9.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is open-webui affected?
Yes, open-webui is affected in releases prior to 0.9.0. Upgrade your dependency to 0.9.0 or later.
What is the CVSS score of CVE-2026-45399?
CVE-2026-45399 has a CVSS v3.1 base score of 7.1 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H.
What CWE is associated with CVE-2026-45399?
CVE-2026-45399 is classified under CWE-862: Missing Authorization (The product does not perform an authorization check when an actor attempts to access a resource or perform an action.).
How can I check PyPI dependencies for CVE-2026-45399?
Run the dependency tree command: 'pip show open-webui'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8jjp-r2w2-4v22",
  "modified" : "2026-05-15T23:54:50Z",
  "published" : "2026-05-14T20:26:49Z",
  "aliases" : [ "CVE-2026-45399" ],
  "summary" : "Open WebUI: Low-privilege authenticated users can enumerate and stop global background tasks, causing system-wide chat disruption",
  "details" : "### 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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "open-webui"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.9.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 0.8.12"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/security/advisories/GHSA-8jjp-r2w2-4v22"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-45399"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/pull/23454"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/commit/e7ff4768f8ffe1924b4576381c9e45e8a64350e4"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/open-webui/open-webui"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/releases/tag/v0.9.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-862" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-14T20:26:49Z",
    "nvd_published_at" : "2026-05-15T20:16:48Z"
  }
}