AI and data stack advisories

Severe, 6 weeks1496Projects326

1496 severe, 6 weeks · 326 projects

Open WebUIGHSA-vrhc-3fr6-pc3c

Open WebUI: Forged chat-file link allows cross-user file read and deletion

Open WebUI

CVE-2026-54010 · Published Jun 17, 2026 · updated Jul 20, 2026

High8.3
Fix: upgrade to 0.9.6 or later
GitHub advisory

Summary

Open WebUI v0.9.5 lets an authenticated user attach arbitrary file_id values to their own chat message without checking whether they own or can read those files. If the attacker then shares that chat and grants themselves read access, has_access_to_file() treats the victim file as accessible through the shared chat, and the file endpoints read or delete the victim file.

Impact

Security boundary crossed: file confidentiality and integrity.

An authenticated attacker who knows or obtains a victim file_id can make Open WebUI authorize, through an attacker-owned shared chat:

  • reading the victim file via GET /api/v1/files/{id}/content, and
  • deleting the victim file via DELETE /api/v1/files/{id}.

Root Cause

Client-controlled message file IDs are persisted without file authorization checks:

```python

backend/open_webui/main.py

await Chats.insert_chat_files(

chat_id,

user_message.get('id'),

[

file_item.get('id')

for file_item in user_message_files

if file_item.get('type') == 'file'

],

user.id,

)

`

insert_chat_files() stores the provided IDs directly:

```python

backend/open_webui/models/chats.py

ChatFileModel(

user_id=user_id,

chat_id=chat_id,

message_id=message_id,

file_id=file_id,

)

`

Later, file authorization trusts shared-chat associations:

```python

#...

Affected versions

PackageAffectedFixed in
open-webui
PyPI
< 0.9.60.9.6
Details and references

## Summary Open WebUI `v0.9.5` lets an authenticated user attach arbitrary `file_id` values to their own chat message without checking whether they own or can read those files. If the attacker then shares that chat and grants themselves read access, `has_access_to_file()` treats the victim file as accessible through the shared chat, and the file endpoints read or delete the victim file. ## Impact Security boundary crossed: file confidentiality and integrity. An authenticated attacker who knows or obtains a victim `file_id` can make Open WebUI authorize, through an attacker-owned shared chat: - reading the victim file via `GET /api/v1/files/{id}/content`, and - deleting the victim file via `DELETE /api/v1/files/{id}`. ## Root Cause Client-controlled message file IDs are persisted without file authorization checks: ```python # backend/open_webui/main.py await Chats.insert_chat_files( chat_id, user_message.get('id'), [ file_item.get('id') for file_item in user_message_files if file_item.get('type') == 'file' ], user.id, ) ``` `insert_chat_files()` stores the provided IDs directly: ```python # backend/open_webui/models/chats.py ChatFileModel( user_id=user_id, chat_id=chat_id, message_id=message_id, file_id=file_id, ) ``` Later, file authorization trusts shared-chat associations: ```python # backend/open_webui/utils/access_control/files.py shared_chat_ids = await Chats.get_shared_chat_ids_by_file_id(file_id, db=db) if shared_chat_ids: accessible_ids = await AccessGrants.get_accessible_resource_ids( user_id=user.id, resource_type='shared_chat', resource_ids=shared_chat_ids, permission='read', ) if accessible_ids: return True ``` The download endpoint uses this helper: ```python # backend/open_webui/routers/files.py if file.user_id == user.id or user.role == 'admin' or await has_access_to_file(id, 'read', user, db=db): return FileResponse(file_path, ...) ``` On affected versions this shared-chat branch is not gated on `access_type` (the grant lookup hardcodes `permission='read'`, but nothing checks that the request itself is a read). The same forged association therefore also satisfies the `write` check that `DELETE /api/v1/files/{id}` performs, so the attacker can delete the victim file, not only read it. Because the shared-chat branch ignores `access_type`, the deletion does not require the forged association at all. A user granted only **read** access to a chat that the owner legitimately shared can delete the owner's own files attached to that chat via `DELETE /api/v1/files/{id}`, since the read grant satisfies the `write` check. The forged association (above) broadens this to any victim `file_id`; a legitimate read-only share reaches it without any forgery. ## PoC 1. Attacker creates or uses a chat they own. 2. Attacker sends `POST /api/chat/completions` or `POST /api/v1/chat/completions` where top-level `user_message.files` contains: ```json [ { "type": "file", "id": "VICTIM_FILE_ID" } ] ``` 3. Backend inserts a `chat_file` row linking the attacker chat to `VICTIM_FILE_ID`. 4. Attacker shares the chat and grants read access to themselves or public access. 5. Attacker requests: ```text GET /api/v1/files/VICTIM_FILE_ID/content ``` Expected: 404/403 because the attacker does not own or otherwise have access to the victim file. Actual: file authorization succeeds through the attacker-controlled shared-chat association. ## Local Verification I verified the bug locally with Open WebUI's real `Chats.insert_chat_files()` and real `has_access_to_file()` implementations. The harness uses fake DB adapters only to avoid this environment's async SQLite hang; the security-sensitive logic under test is the application code. Result: ```json { "before_chat_file_link_attacker_can_read": false, "insert_sink": { "db_commit_called": true, "insert_returned_rows": true, "stored_chat

CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L
Severity from
GitHub (reviewed advisory)
Weakness
CWE-284, CWE-639, CWE-862
Also known as
CVE-2026-54010, PYSEC-2026-2763

More Open WebUI advisories

All Open WebUI