Skip to content

Commit 87f8e5d

Browse files
jmelahmanclaude
andauthored
fix(security): enforce chat session ownership on stop endpoint (#10413) to release v3.2 (#10417)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 5ef8a33 commit 87f8e5d

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

backend/onyx/server/query_and_chat/chat_backend.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,11 +986,21 @@ async def search_chats(
986986
@router.post("/stop-chat-session/{chat_session_id}", tags=PUBLIC_API_TAGS)
987987
def stop_chat_session(
988988
chat_session_id: UUID,
989-
user: User = Depends(require_permission(Permission.BASIC_ACCESS)), # noqa: ARG001
989+
user: User = Depends(require_permission(Permission.BASIC_ACCESS)),
990+
db_session: Session = Depends(get_session),
990991
) -> dict[str, str]:
991992
"""
992993
Stop a chat session by setting a stop signal.
993994
This endpoint is called by the frontend when the user clicks the stop button.
994995
"""
996+
try:
997+
get_chat_session_by_id(
998+
chat_session_id=chat_session_id,
999+
user_id=user.id,
1000+
db_session=db_session,
1001+
)
1002+
except ValueError:
1003+
raise OnyxError(OnyxErrorCode.SESSION_NOT_FOUND, "Chat session not found")
1004+
9951005
set_fence(chat_session_id, get_cache_backend(), True)
9961006
return {"message": "Chat session stopped"}

backend/tests/integration/tests/chat/test_chat_session_access.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,30 @@ def test_chat_session_not_found_returns_404(basic_user: DATestUser) -> None:
183183
"""Verify unknown IDs return 404."""
184184
response = _get_chat_session(str(uuid4()), basic_user)
185185
assert response.status_code == 404
186+
187+
188+
def _stop_chat_session(chat_session_id: str, user: DATestUser) -> requests.Response:
189+
return requests.post(
190+
f"{API_SERVER_URL}/chat/stop-chat-session/{chat_session_id}",
191+
headers=user.headers,
192+
cookies=user.cookies,
193+
)
194+
195+
196+
def test_stop_chat_session_rejects_non_owner(
197+
basic_user: DATestUser, second_user: DATestUser
198+
) -> None:
199+
"""Non-owner callers must not be able to stop another user's chat session."""
200+
chat_session = ChatSessionManager.create(user_performing_action=basic_user)
201+
202+
# Owner can stop their own session.
203+
response = _stop_chat_session(str(chat_session.id), basic_user)
204+
assert response.status_code == 200
205+
206+
# A different authenticated user must not be able to stop it.
207+
response = _stop_chat_session(str(chat_session.id), second_user)
208+
assert response.status_code == 404
209+
210+
# Unknown session IDs are also rejected.
211+
response = _stop_chat_session(str(uuid4()), second_user)
212+
assert response.status_code == 404

0 commit comments

Comments
 (0)