Skip to content

AGENT_ID isolated scope not enforced on mem::search (REST /search, memory_recall, recall_context) → cross-agent memory leak #817

Description

@nnachname90

Summary

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.

Repro

  1. Start: AGENT_ID=agent_a AGENTMEMORY_AGENT_SCOPE=isolated npx @agentmemory/agentmemory
  2. POST /agentmemory/remember {"content":"SECRET_MARKER private to A"} → stored with agentId=agent_a
  3. Restart against the same data dir with AGENT_ID=agent_b AGENTMEMORY_AGENT_SCOPE=isolated
  4. POST /agentmemory/smart-search {"query":"SECRET_MARKER"}0 results ✅ (correctly isolated)
  5. POST /agentmemory/search {"query":"SECRET_MARKER"}returns A's memory ❌ (leak)
  6. 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.ts api::search (~L364–432): builds payload without agentId.
  • src/mcp/server.ts memory_recall (~L115) and recall_context (~L1640) both call function_id: "mem::search"; recall_context additionally kv.list(KV.memories) filtered only by isLatest.
  • CHANGELOG (PR feat(scope): AGENT_ID multi-agent isolation; docs(cost,supply-chain) #654) enumerates the filtered paths and omits mem::search.

Impact

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions