From 3f1c52e0182d6c7af58c9e52672d242a1dfff66f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 29 May 2026 00:42:17 +0200 Subject: [PATCH] fix: gate chat-file links by caller access + repair insert_chat_files db arg (#25054) insert_chat_files() stored any caller-supplied file_id with no ownership check, so a user could attach another user's file to their own chat and then read it through the shared-chat access path in has_access_to_file(). Filter file_ids to those the caller owns, is admin for, or can read. Also repairs an UnboundLocalError introduced in 260ead64d: the existing duplicate-check referenced `session` before it was assigned (db=session), so the function threw on every call and no chat_file rows were persisted. --- backend/open_webui/models/chats.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index b7cdece2d5..63a8bb1f2e 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -1624,13 +1624,34 @@ class ChatTable: return None chat_message_file_ids = { - item.id for item in await self.get_chat_files_by_chat_id_and_message_id(chat_id, message_id, db=session) + item.id for item in await self.get_chat_files_by_chat_id_and_message_id(chat_id, message_id, db=db) } # Remove duplicates and existing file_ids file_ids = list({file_id for file_id in file_ids if file_id and file_id not in chat_message_file_ids}) if not file_ids: return None + # Only link files the caller can read; blocks forging a chat_file row to another user's file. + from open_webui.models.files import Files + from open_webui.models.users import Users + from open_webui.utils.access_control.files import has_access_to_file + + user = await Users.get_user_by_id(user_id, db=db) + accessible_file_ids = [] + for file_id in file_ids: + file = await Files.get_file_by_id(file_id, db=db) + if not file: + continue + if ( + file.user_id == user_id + or (user and user.role == 'admin') + or (user and await has_access_to_file(file_id, 'read', user, db=db)) + ): + accessible_file_ids.append(file_id) + file_ids = accessible_file_ids + if not file_ids: + return None + try: async with get_async_db_context(db) as session: now = int(time.time())