RAG and data leaks: how knowledge-base search becomes an exfiltration channel
RAG is the most popular way to give an LLM access to company knowledge: documents go into a vector index, the model searches them and answers with citations. It is also the most frequent leak channel in our audits: the bot faithfully finds and retells a document this user must not see. Here is exactly where RAG architectures leak.
Why RAG leaks: permissions are checked in the wrong place
The classic mistake: all company documents are indexed into one shared vector index, search runs over the whole index, and the user's permissions are checked "somewhere in the app" — or not at all. Then a well-phrased question is enough: "what does the latest salary report say?", "quote the contract with client X" — and the model dutifully answers from a document the asker has no access to.
Worse: even if direct quoting is forbidden by the prompt, the foreign document's content is already in the model's context — and gets extracted indirectly: through paraphrase, through "compare with…", through a translation request. The only reliable boundary is to keep the document out of the context entirely.
Four typical leak scenarios
- ◇A shared index without ACLs: permissions are not attached to documents, any user searches the entire corpus. The most common and crudest case — found even in enterprise products.
- ◇Post-retrieval filtering: documents are fetched from the index first, then dropped by permissions. A filter bug, updated permissions, a document with mixed access levels — and the "dropped" text ends up in the context anyway. Filtering must happen in the index query itself.
- ◇Leaks through metadata and embeddings: even without content, the mere existence of a document ("Company Y acquisition agreement.docx" in the source list) is a leak. Titles, authors and dates in citations need the same permissions as the text.
- ◇A poisoned document: an injection in a file that reaches the index — an email, a ticket, a user-uploaded document. The model reads it while answering another user and executes the embedded command: distorts the answer, extracts data from the dialogue, calls tools. That is no longer just a leak — it is channel takeover.
How this is tested in an audit
Testing RAG is essentially an access-control pentest through a language interface. We take two accounts with different permissions and methodically check whether user A can reach user B's documents: direct questions, rephrasing, metadata search, multi-turn dialogues. A separate block is injections: we place a document with a command into any writable location (a ticket, a comment, an uploadable file) and watch whether the model executes it when answering other users.
Every finding is documented with a dialogue transcript — evidence that cannot be dismissed with "the model wouldn't answer that". It does, and the report shows it.
How to build RAG that does not leak
- ◇Permissions at retrieval time: the ACL filter is part of the index query itself (metadata filtering, per-tenant indexes or namespaces). Nothing foreign in the context — nothing to leak.
- ◇Permission inheritance from the source: a document in the index carries the same permissions as in the source system (drive, wiki, CRM), synchronized on change, not once at indexing time.
- ◇Metadata under the same permissions as text: citations, titles and source lists are filtered like content.
- ◇Index input control: anything entering the knowledge base from external or user sources is treated as untrusted — marked as data, never allowed to command the model.
- ◇Query and retrieval logging: which documents entered which dialogue's context — without this a leak can be neither detected nor scoped.
FAQ
A 2-day express assessment: two accounts, foreign documents, injections through the knowledge base. A short report with transcripts of proven findings.
Book an express assessment