Found while verifying the endpoint audit in PR #14009 (#13982). Same vulnerability class, different router — and unlike the flag-gated checks, this one is simply never called.
Problem
export_session (autobot-backend/api/chat_sessions.py, GET /chat/sessions/{session_id}/export) takes session_id from the path and calls neither validate_session_ownership nor validate_chat_ownership anywhere in its body:
async def export_session(session_id: str, request: Request, format: str = "json"):
_validate_session_id_or_raise(session_id)
_validate_export_format_or_raise(format)
...
session_data = await _export_session_data_or_raise(chat_history_manager, session_id, format)
The only guards are a session-id format check and a format check. Verified by reading the full function, not by grepping for the word "ownership".
Impact
Any authenticated user who knows or guesses another user's session_id can export that user's entire chat transcript. This is bulk disclosure of conversation content, which is a worse outcome than the injection gap #13982 covered, and it is not feature-flag dependent — there is no check to enable.
Session ids are the same values that appear in URLs and are referenced across the chat APIs, so "knows or guesses" is not a high bar in practice.
Suggested fix
Add the ownership check the sibling endpoints use, before any data is read:
await validate_chat_ownership(session_id, request) # SECURITY: caller must own the session
Then audit the rest of api/chat_sessions.py the same way — by reading each function that accepts a session_id, not by grepping. #14009's audit covered api/chat.py only; the assumption that a sibling router was equally covered turned out to be wrong, which is the reason to check the rest by hand.
Acceptance criteria
Note on enforcement
Adding the call closes the missing-check gap, but the shared validator currently fails open — see #14010. Both are needed for this endpoint to actually refuse a non-owner in a default deployment.
Related
Found while verifying the endpoint audit in PR #14009 (#13982). Same vulnerability class, different router — and unlike the flag-gated checks, this one is simply never called.
Problem
export_session(autobot-backend/api/chat_sessions.py,GET /chat/sessions/{session_id}/export) takessession_idfrom the path and calls neithervalidate_session_ownershipnorvalidate_chat_ownershipanywhere in its body:The only guards are a session-id format check and a format check. Verified by reading the full function, not by grepping for the word "ownership".
Impact
Any authenticated user who knows or guesses another user's
session_idcan export that user's entire chat transcript. This is bulk disclosure of conversation content, which is a worse outcome than the injection gap #13982 covered, and it is not feature-flag dependent — there is no check to enable.Session ids are the same values that appear in URLs and are referenced across the chat APIs, so "knows or guesses" is not a high bar in practice.
Suggested fix
Add the ownership check the sibling endpoints use, before any data is read:
Then audit the rest of
api/chat_sessions.pythe same way — by reading each function that accepts asession_id, not by grepping. #14009's audit coveredapi/chat.pyonly; the assumption that a sibling router was equally covered turned out to be wrong, which is the reason to check the rest by hand.Acceptance criteria
export_sessionrefuses asession_idthe caller does not owninspect.getsource)api/chat_sessions.pythat accepts a session id is audited by reading the function body; the result is listed in the PR, including any found unprotectedNote on enforcement
Adding the call closes the missing-check gap, but the shared validator currently fails open — see #14010. Both are needed for this endpoint to actually refuse a non-owner in a default deployment.
Related
api/chat.py