Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions backend/open_webui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,16 @@
from open_webui.utils.redis import get_sentinels_from_env


def can_update_chat(chat_id: Optional[str], user: UserModel) -> bool:
if not chat_id:
return False

if user.role == "admin" and ENABLE_ADMIN_CHAT_ACCESS:
return Chats.get_chat_by_id(chat_id) is not None

return Chats.get_chat_by_id_and_user_id(chat_id, user.id) is not None


if SAFE_MODE:
print("SAFE MODE ENABLED")
Functions.deactivate_all_functions()
Expand Down Expand Up @@ -1351,6 +1361,12 @@ async def chat_completion(
),
}

if metadata.get("chat_id") and not can_update_chat(metadata["chat_id"], user):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Chat not found",
)

request.state.metadata = metadata
form_data["metadata"] = metadata

Expand All @@ -1360,7 +1376,11 @@ async def chat_completion(

except Exception as e:
log.debug(f"Error processing chat payload: {e}")
if metadata.get("chat_id") and metadata.get("message_id"):
if (
metadata.get("chat_id")
and metadata.get("message_id")
and can_update_chat(metadata["chat_id"], user)
):
# Update the chat message with the error
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
Expand All @@ -1370,6 +1390,9 @@ async def chat_completion(
},
)

if isinstance(e, HTTPException):
raise e

raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
Expand All @@ -1383,7 +1406,11 @@ async def chat_completion(
)
except Exception as e:
log.debug(f"Error in chat completion: {e}")
if metadata.get("chat_id") and metadata.get("message_id"):
if (
metadata.get("chat_id")
and metadata.get("message_id")
and can_update_chat(metadata["chat_id"], user)
):
# Update the chat message with the error
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
Expand All @@ -1393,6 +1420,9 @@ async def chat_completion(
},
)

if isinstance(e, HTTPException):
raise e

raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
Expand Down
46 changes: 46 additions & 0 deletions backend/open_webui/test/apps/webui/routers/test_chats.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,49 @@ def test_delete_shared_chat_by_id(self):

chat = self.chats.get_chat_by_id(chat_id)
assert chat.share_id is None

def test_chat_completion_error_does_not_update_other_users_chat(self):
from open_webui.models.chats import ChatForm

victim_message_id = "victim-message"
victim_chat = self.chats.insert_new_chat(
"2",
ChatForm(
chat={
"title": "Victim chat",
"history": {
"currentId": victim_message_id,
"messages": {
victim_message_id: {
"id": victim_message_id,
"role": "assistant",
"content": "do not overwrite",
}
},
},
}
),
)

with mock_webui_user(id="3", role="user"):
response = self.fast_api_client.post(
"/api/chat/completions",
json={
"model": "attacker-direct",
"model_item": {
"id": "attacker-direct",
"direct": True,
"owned_by": "openai",
"info": {"meta": {}},
},
"chat_id": victim_chat.id,
"id": victim_message_id,
},
)

assert response.status_code == 403
message = self.chats.get_message_by_id_and_message_id(
victim_chat.id, victim_message_id
)
assert message["content"] == "do not overwrite"
assert "error" not in message