Open WebUI: Forged chat-file link allows cross-user file read and deletion
High8.3CVE-2026-54010 · Published Jun 17, 2026 · updated Jul 20, 2026
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| open-webui PyPI | < 0.9.6 | 0.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
- github.com/open-webui/open-webui/security/advisories/GHSA-vrhc-3fr6-pc3c
- nvd.nist.gov/vuln/detail/CVE-2026-54010
- github.com/open-webui/open-webui/pull/24755
- github.com/open-webui/open-webui/pull/25054
- github.com/advisories/GHSA-vrhc-3fr6-pc3c
- github.com/open-webui/open-webui
- github.com/pypa/advisory-database/tree/main/vulns/open-webui/PYSEC-2026-2763.yaml
- pypi.org/project/open-webui
More Open WebUI advisories
All Open WebUI| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Jun 17 | Open WebUI IDOR: Calendar event re-parenting allows writing events into another user's calendar CVE-2026-54006Medium4.3fixed in 0.9.6 | Medium4.3 | 0.9.6 |
| Jun 17 | Open WebUI: Cross-origin postMessage confirmation bypass via action:submit CVE-2026-54007High6.5fixed in 0.9.6 | High6.5 | 0.9.6 |
| Jun 17 | Open WebUI: Redirect-Bypass SSRF in OAuth `_process_picture_url` (incomplete-fix sibling of CVE-2026-45401) CVE-2026-54008High8.5fixed in 0.9.6 | High8.5 | 0.9.6 |
| Jun 17 | Open WebUI: Cross-user file disclosure via /api/chat/completions image_url field CVE-2026-54009Medium6.5fixed in 0.9.6 | Medium6.5 | 0.9.6 |
| Jun 17 | Open WebUI: Stored XSS in Mermaid Markdown Preview CVE-2026-54011High8.7fixed in 0.9.6 | High8.7 | 0.9.6 |
| Jun 17 | Open WebUI: Forged model meta.knowledge allows cross-user file read and deletion CVE-2026-54012High7.1fixed in 0.9.6 | High7.1 | 0.9.6 |