mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 10:15:27 -04:00
fix(research): gate /api/research/spinoff on session ownership (#878)
The spinoff endpoint authenticated the caller (_require_user) but never verified the research session belonged to them before reading the persisted report and seeding it into a new chat session owned by the caller. Any authenticated user who knew or guessed another user's research session ID could exfiltrate that user's full report into their own session — a cross-user data disclosure (IDOR). Every other endpoint in this router gates on _owns_in_memory / _assert_owns_research right after validating the session ID; spinoff was the lone exception. Add the same _owns_in_memory check (covers both the in-memory task and the on-disk JSON) so a non-owner gets a 404 before any data is read or a session is created. Add regression tests pinning the anonymous (401) and wrong-owner (404) cases.
This commit is contained in:
@@ -492,8 +492,14 @@ def setup_research_routes(research_handler, session_manager=None) -> APIRouter:
|
||||
injects a single system message containing the report and sources so
|
||||
the user can ask follow-up questions in a clean conversation.
|
||||
"""
|
||||
_require_user(request)
|
||||
user = _require_user(request)
|
||||
_validate_session_id(session_id)
|
||||
# SECURITY: gate on ownership before reading the persisted research —
|
||||
# otherwise any authenticated user could spin off (and thereby read)
|
||||
# another user's report by guessing its session ID. Mirrors every other
|
||||
# endpoint in this file (see result_peek above).
|
||||
if not _owns_in_memory(session_id, user):
|
||||
raise HTTPException(404, "No research found for this session")
|
||||
if session_manager is None:
|
||||
raise HTTPException(500, "session_manager not configured")
|
||||
|
||||
@@ -574,7 +580,6 @@ def setup_research_routes(research_handler, session_manager=None) -> APIRouter:
|
||||
|
||||
# Create new session
|
||||
new_sid = str(uuid.uuid4())
|
||||
user = get_current_user(request)
|
||||
|
||||
title_query = (query or "research").strip()
|
||||
if len(title_query) > 60:
|
||||
|
||||
Reference in New Issue
Block a user