AI and data stack advisories

Severe, 6 weeks1496Projects326

1496 severe, 6 weeks · 326 projects

Open WebUIGHSA-73x5-h92w-xc2j

Open WebUI: Private channel messages can be disclosed through cross-channel thread parent_id binding

Open WebUI

CVE-2026-59215 · Published Jul 24, 2026 · updated Aug 4, 2026

Low3.1
Fix: upgrade to 0.10.0 or later
GitHub advisory

Summary

A normal authenticated user can read the content of a message in a private channel they do not belong to. GET /api/v1/channels/{id}/messages/{message_id}/thread authorizes the caller against the URL channel, but the underlying thread lookup loads the thread *parent* by id and returns it without verifying the parent belongs to that channel. By requesting a thread in a channel they can access while supplying a victim channel's message id as the thread root, the attacker receives the victim message , content, channel id, and author.

Affected component

  • backend/open_webui/models/messages.py , get_messages_by_parent_id()
  • backend/open_webui/routers/channels.py , get_channel_thread_messages() (read), new_message_handler() (parent/reply binding on write)

Root cause

get_messages_by_parent_id(channel_id, parent_id) filters the thread *replies* by channel_id, but loads the thread *parent* by id alone and appends it without requiring parent.channel_id == channel_id:

```python

message = await db.get(Message, parent_id) # loaded by id only , no channel binding

if not message:

return []

replies are filtered by channel_id ...

if len(all_messages) < limit:

all_messages.append(message) # parent appended unconditionally

`

get_channel_thread_messages() authorizes only the URL channel, then calls...

Affected versions

PackageAffectedFixed in
open-webui
PyPI
< 0.10.00.10.0
Details and references

## Summary A normal authenticated user can read the content of a message in a private channel they do not belong to. `GET /api/v1/channels/{id}/messages/{message_id}/thread` authorizes the caller against the URL channel, but the underlying thread lookup loads the thread *parent* by id and returns it without verifying the parent belongs to that channel. By requesting a thread in a channel they can access while supplying a victim channel's message id as the thread root, the attacker receives the victim message , content, channel id, and author. ## Affected component - `backend/open_webui/models/messages.py` , `get_messages_by_parent_id()` - `backend/open_webui/routers/channels.py` , `get_channel_thread_messages()` (read), `new_message_handler()` (parent/reply binding on write) ## Root cause `get_messages_by_parent_id(channel_id, parent_id)` filters the thread *replies* by `channel_id`, but loads the thread *parent* by id alone and appends it without requiring `parent.channel_id == channel_id`: ```python message = await db.get(Message, parent_id) # loaded by id only , no channel binding if not message: return [] # replies are filtered by channel_id ... if len(all_messages) < limit: all_messages.append(message) # parent appended unconditionally ``` `get_channel_thread_messages()` authorizes only the URL channel, then calls `get_messages_by_parent_id(id, message_id)` with the caller-supplied `message_id`. The reply insert path (`new_message_handler` → `insert_new_message`) also stored a caller-supplied `parent_id` without binding it to the channel. ## Impact A non-member can disclose the content (plus channel id and author metadata) of a private-channel message whose id they know or obtain. Direct reads of the victim channel/message/thread return 403; the disclosure is via the thread parent of a channel the attacker can access. Read-only, one message per known id. ## Proof of Concept (reporter) Validated on v0.9.6: `GET /channels/{attacker_channel}/messages/{victim_message_id}/thread` returned the victim's private message , content, victim channel id, and author , although direct reads of the victim channel returned 403. ## Fix Bind the thread parent to the requested channel: `get_messages_by_parent_id` returns `[]` unless the parent exists and `parent.channel_id == channel_id`. Defence-in-depth on the write path: `new_message_handler` rejects a supplied `parent_id`/`reply_to_id` whose message does not belong to the URL channel. ## Affected / Patched - Affected: `< 0.10.0` (last affected release 0.9.6) - Patched: v0.10.0 (PR #25766). `get_messages_by_parent_id` binds the thread parent to the requested channel (returns `[]` unless `parent.channel_id == channel_id`), and `new_message_handler` rejects a caller-supplied `parent_id`/`reply_to_id` whose message does not belong to the channel.

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

More Open WebUI advisories

All Open WebUI