From c609ec41154fa092fa0af80d9d365de06b666286 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 24 Jul 2026 05:40:03 +0200 Subject: [PATCH] fix: require message authorship for standard-channel message edit and delete (#27197) The channel message update and delete handlers enforced authorship only on group and dm channels. On standard channels the else branch accepted any caller holding write access on the channel, so a member who could post could also edit or delete messages authored by other members. Because the update form binds content, data and meta, and the model layer never touches message.user_id, an edited message kept the original author's attribution, so another member's message could be rewritten under their name. Write access on a channel is the capability to post, not a moderation capability, and the frontend gates the edit and delete controls on authorship (message.user_id === user.id, or admin) for every channel type. The group and dm branch already encodes this with an explicit authorship check. Apply the same rule to the standard branch: the caller must hold write access on the channel and be the message author, unless they are an admin. Pinning is unchanged, since it is exposed to every member by design. --- backend/open_webui/routers/channels.py | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index 6b891bdadf..64413fa74e 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -1500,12 +1500,13 @@ async def update_message_by_id( if user.role != 'admin' and message.user_id != user.id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) else: - if ( - user.role != 'admin' - and message.user_id != user.id - and not await channel_has_access(user.id, channel, permission='write', strict=False, db=db) + if user.role != 'admin' and not await channel_has_access( + user.id, channel, permission='write', strict=False, db=db ): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) + # Write access is not authorship — block cross-member edits. + if user.role != 'admin' and message.user_id != user.id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) try: await Messages.update_message_by_id(message_id, form_data, db=db) @@ -1725,18 +1726,17 @@ async def delete_message_by_id( if user.role != 'admin' and message.user_id != user.id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) else: - if ( - user.role != 'admin' - and message.user_id != user.id - and not await channel_has_access( - user.id, - channel, - permission='write', - strict=False, - db=db, - ) + if user.role != 'admin' and not await channel_has_access( + user.id, + channel, + permission='write', + strict=False, + db=db, ): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) + # Write access is not authorship — block cross-member deletes. + if user.role != 'admin' and message.user_id != user.id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) try: await Messages.delete_message_by_id(message_id, db=db)