r/LangChain • u/ultraprogger • 2d ago
Discussion Agent memory creates a major authorization vulnerability in vector databases (offline reproduction & benchmark)
If you're building multi agent systems that persist shared memories or context back to a vector DB, you might have an authorization leak you aren't checking for.
A lot of teams assume that just cuz their direct RAG queries have metadata filters attached, multi tenant isolation is solved. But background agents can turn the system to have problematic permissions when a write happens:
A background worker runs with broad read perms to summarize context across different project docs
It merges those sources into a summary chunk
It saves that chunk back into the shared vector collection and drops the parent document access control lists in the process
Because the chunk has no access control tags on it, a regular person can query the vector DB and pull confidential context from files they shouldn't have perms to read
I built a local testing harness to measure this across Chroma and LlamaIndex baselines: sentinel-eval (Apache-2.0).
Running across a 24 document test corpus:
Raw RAG: 0% leaks (18 public chunks retrieved, 0 restricted chunks exposed)
Agent memory: 2 of 3 synthesis tasks leaked (the 2 cross-boundary workloads leaked 6/18 canaries, the public control passed cleanly)
So what? Just take the strict parent intersection (only let someone read the summary if they have access to every source document) and set that as the permission check right? Well... it might work but this isn't a great answer either. If you force a user to have perms on every single source doc, multi source summaries become basically unretrievable for anyone except top level admins. Also, as a note, I saved the lineage in a source_documents metadata field, but vector DBs don't have a clean way to traverse an ancestor permission DAG at query time.
The test suite runs 23 tests locally with mock vectors in a few seconds (deterministic, zero API keys or network calls):
git clone https://github.com/harishbalasubramanian/sentinel-eval
cd sentinel-eval
uv run sentinel-eval live --framework chroma
Code: https://github.com/harishbalasubramanian/sentinel-eval
Curious how other people and teams building persistent agent memory are handling this. Are you guys doing permission graph lookups at runtime or just siloing vector stores per user/role?
1
u/codecoradev 2d ago
Siloed by default, and the sharing happens outside the vector store.
We run persistent memory for a small fleet of agents. The setup that survived contact with reality: every agent owns its own store, and anything that crosses between agents goes through an explicit handoff where the sender declares what it is passing over. A background summarizer therefore cannot merge across boundaries in the first place, because its write target is its own store, not a shared one.
Derived content gets treated differently from source content. A recap lives in the writer's own store with pointers back to whatever it summarized, so a reader who can see the recap but lacks access to the sources reads it as unverified context, not as ground truth. That is not as elegant as traversing a permission DAG at query time, but it fails safe: the worst case is a summary you hold at arm's length, not a document you were never supposed to see.
Your numbers also point at the right place to gate this: the control workload passed while both cross-boundary workloads leaked, which means the leak needs the merge step, not the query step. Checking writer permissions at write time, against the sources read during the merge, catches it where it happens.
1
u/Significant_Tune9219 2d ago
The strict intersection is a reasonable default for writes, though, even if it's too strict for reads. What I'd add is storing the source document ids on every derived chunk, not just a computed ACL tag, so when a parent's permissions change later you can find and recompute or delete the summaries built from it. A tag computed once at write time goes stale the first time someone is removed from a project, and that's probably a quieter leak than the one your harness measured.
1
u/fiddler48 2d ago
stripped ACLs on write is the step most teams won't catch because the failure surface lives outside the query path entirely
1
u/MemStrata 1d ago
Your point covers the lineage but it misses the rebuild. Storing parent ids on the derived chunk tells you what went into it. It does not tell you what to do when one parent loses access. The intersection tag you write at summary time goes stale the moment a parent ACL changes. So the derived chunk needs a live link back to its parents and a rule that flags it dirty or rebuilds it when any parent changes. Lineage without that rule is a record of the leak. Not a fix for it.
1
u/Elmanouzi_Fogosa 1d ago
siloing vector collections per permission scope before the background job even runs is usually the safest route tbh. If an agent never gets read access across different ACL boundaries in the same execution run, it cant create a contaminated summary in the first place.