From c132b6d2e65ccfb07da0377b5b704b918ec029fe Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 6 Jun 2026 17:14:17 +0200 Subject: [PATCH] fix: bind channel thread parent/reply to the URL channel GET /api/v1/channels/{id}/messages/{message_id}/thread authorized only the URL channel, but get_messages_by_parent_id() appended the thread parent (loaded by id) without checking it belonged to that channel, so a caller could read a message from a channel they cannot access by passing its id as the thread root. Require the parent to be in the requested channel before returning it, and reject a posted parent_id/reply_to_id that does not belong to the channel. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/open_webui/models/messages.py | 3 ++- backend/open_webui/routers/channels.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index 342abed2f8..64096d69d8 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -328,7 +328,8 @@ class MessageTable: async with get_async_db_context(db) as db: message = await db.get(Message, parent_id) - if not message: + # Thread parent must belong to the requested channel; never disclose a foreign-channel message. + if not message or message.channel_id != channel_id: return [] result = await db.execute( diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index 11d3a4a871..2877dfe281 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -1036,6 +1036,13 @@ async def new_message_handler(request: Request, id: str, form_data: MessageForm, ): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) + # Thread parent / reply target must belong to this channel (no cross-channel binding). + for ref_id in (form_data.parent_id, form_data.reply_to_id): + if ref_id: + ref = await Messages.get_message_by_id(ref_id, include_thread_replies=False, db=db) + if not ref or ref.channel_id != channel.id: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()) + try: message = await Messages.insert_new_message(form_data, channel.id, user.id, db=db) if message: