You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With AGENTMEMORY_AGENT_SCOPE=isolated, recall is correctly filtered on mem::smart-search, /memories, /observations, /sessions (per CHANGELOG, PR #654). However mem::search applies no agent-scope filtering at all — and it backs the REST POST /agentmemory/search endpoint and the MCP tools memory_recall and recall_context. An isolated worker for agent B can therefore read memories tagged for agent A.
Environment
v0.9.26, local engine (no API key, BM25-only), Linux, Node 25.
POST /agentmemory/remember {"content":"SECRET_MARKER private to A"} → stored with agentId=agent_a
Restart against the same data dir with AGENT_ID=agent_b AGENTMEMORY_AGENT_SCOPE=isolated
POST /agentmemory/smart-search {"query":"SECRET_MARKER"} → 0 results ✅ (correctly isolated)
POST /agentmemory/search {"query":"SECRET_MARKER"} → returns A's memory ❌ (leak)
memory_recall (MCP) → same leak, since it calls mem::search
Root cause
src/functions/search.ts (mem::search): no getAgentId() / isAgentScopeIsolated() usage.
src/triggers/api.tsapi::search (~L364–432): builds payload without agentId.
src/mcp/server.tsmemory_recall (~L115) and recall_context (~L1640) both call function_id: "mem::search"; recall_context additionally kv.list(KV.memories) filtered only by isLatest.
memory_recall is a primary recall tool, so the isolation guarantee is bypassed in normal agent usage — not just via a raw REST call. Anyone relying on isolated for multi-tenant separation is exposed.
Suggested fix
Make mem::search honor isAgentScopeIsolated() / getAgentId() and filter results (mirroring mem::smart-search), and have api::search / memory_recall / recall_context propagate agentId + ?agentId query param consistently with the other recall paths.
Summary
With
AGENTMEMORY_AGENT_SCOPE=isolated, recall is correctly filtered onmem::smart-search,/memories,/observations,/sessions(per CHANGELOG, PR #654). Howevermem::searchapplies no agent-scope filtering at all — and it backs the RESTPOST /agentmemory/searchendpoint and the MCP toolsmemory_recallandrecall_context. An isolated worker for agent B can therefore read memories tagged for agent A.Environment
v0.9.26, local engine (no API key, BM25-only), Linux, Node 25.
Repro
AGENT_ID=agent_a AGENTMEMORY_AGENT_SCOPE=isolated npx @agentmemory/agentmemoryPOST /agentmemory/remember {"content":"SECRET_MARKER private to A"}→ stored withagentId=agent_aAGENT_ID=agent_b AGENTMEMORY_AGENT_SCOPE=isolatedPOST /agentmemory/smart-search {"query":"SECRET_MARKER"}→0 results✅ (correctly isolated)POST /agentmemory/search {"query":"SECRET_MARKER"}→ returns A's memory ❌ (leak)memory_recall(MCP) → same leak, since it callsmem::searchRoot cause
src/functions/search.ts(mem::search): nogetAgentId()/isAgentScopeIsolated()usage.src/triggers/api.tsapi::search(~L364–432): builds payload withoutagentId.src/mcp/server.tsmemory_recall(~L115) andrecall_context(~L1640) both callfunction_id: "mem::search";recall_contextadditionallykv.list(KV.memories)filtered only byisLatest.mem::search.Impact
memory_recallis a primary recall tool, so the isolation guarantee is bypassed in normal agent usage — not just via a raw REST call. Anyone relying onisolatedfor multi-tenant separation is exposed.Suggested fix
Make
mem::searchhonorisAgentScopeIsolated()/getAgentId()and filter results (mirroringmem::smart-search), and haveapi::search/memory_recall/recall_contextpropagateagentId+?agentIdquery param consistently with the other recall paths.