fix(memory): owner-scope memory route session access

This commit is contained in:
Afonso Coutinho
2026-06-03 23:13:56 +01:00
committed by GitHub
parent c58cb067f2
commit b6607d219d
2 changed files with 79 additions and 3 deletions

View File

@@ -39,6 +39,18 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
def _owner(request: Request) -> Optional[str]:
return get_current_user(request)
def _assert_session_owner(session_obj, user):
"""SECURITY: 404 if the caller does not own this session.
SessionManager.get_session is NOT owner-scoped — it returns any
session by id. These routes accept a caller-supplied session id, so
without this gate a user could target another tenant's session and
leak their chat history, their session-scoped LLM credentials, or the
session title. Mirrors session_routes / webhook_routes ownership.
"""
if user is not None and getattr(session_obj, "owner", None) != user:
raise HTTPException(404, "Session not found")
def _verify_memory_owner(memory: dict, user: Optional[str]):
"""Raise 404 if user doesn't own this memory.
@@ -161,12 +173,12 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
@router.get("/by-session/{session_id}")
def get_memory_by_session(request: Request, session_id: str):
"""Get all memories associated with a specific session."""
user = _owner(request)
try:
session_manager.get_session(session_id)
_session_obj = session_manager.get_session(session_id)
except KeyError:
raise HTTPException(404, f"Session {session_id} not found")
user = _owner(request)
_assert_session_owner(_session_obj, user)
memories = memory_manager.load(owner=user)
session_memories = [m for m in memories if m.get("session_id") == session_id]
@@ -196,6 +208,7 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
sess = session_manager.get_session(session)
except KeyError:
raise HTTPException(404, "Session not found")
_assert_session_owner(sess, _owner(request))
system_msg = {
"role": "system",
@@ -277,6 +290,7 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
if not endpoint_url and session:
try:
sess = session_manager.get_session(session)
_assert_session_owner(sess, _owner(request))
endpoint_url = sess.endpoint_url
model = sess.model
headers = sess.headers
@@ -327,6 +341,7 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
if session:
try:
sess = session_manager.get_session(session)
_assert_session_owner(sess, _owner(request))
endpoint_url = sess.endpoint_url
model = sess.model
headers = sess.headers