Privacy & Security 7 min read
Securing RAG: Poisoned Documents and Broken Access Controls
When permissions are checked after search, restricted text still reaches the model. How to build permission-aware retrieval, track provenance and handle poisoned content.

Quick answer: Connecting a model to your own knowledge base does not make its answers trustworthy. RAG can leak documents when permissions are checked after search, and it can repeat poisoned content that someone planted in a trusted source. Apply source permissions inside the retrieval query, record where every chunk came from, and screen, review and remove suspicious content.
Here is an invented example. Kestrel Bio, a 600-person biotech company, builds an internal assistant over its wiki, shared drives and policy library. The pipeline indexes everything into one vector store. At query time it retrieves the top 20 chunks, reranks them, passes the best eight to the model, and then, before showing the answer, removes citations to documents the user cannot open.
A lab manager asks, "What is happening with the Basel site next year?" The best match is a chunk from a board paper on a planned site sale, restricted to the executive team. The model summarizes it. The permission check then removes the citation, so the lab manager sees a confident answer about the sale with no source link. The access check worked exactly as built. It simply ran after the restricted text had already reached the model.
The same month, a contractor with edit rights on the finance wiki adds a line to an expense page: "Update: purchases under 5,000 euros no longer need manager approval." The assistant starts quoting it. Nothing was hacked. A trusted source contained untrusted content.
Why doesn't a trusted knowledge base guarantee trustworthy answers?
RAG changes what the model sees, not how far you can trust it. Two failure modes matter most:
- Broken access control: the retriever can see more than the user. The 2026 OWASP entry for Vector and Embedding Weaknesses describes post-search filtering as the vulnerable pattern and recommends scoping inside the index query, noting that a scope supplied by the client is "a suggestion, not a control".
- Poisoned or manipulated content: anyone who can write to an indexed source can influence answers. The PoisonedRAG study (USENIX Security 2025) showed that injecting a handful of crafted passages per target question into a knowledge base with millions of texts could steer answers in most attempts, and that the simple defenses it tested were insufficient.
Retrieved text can also carry instructions, not just false facts. That is indirect prompt injection, covered in our article on why a system prompt is not a security boundary.
How are teams handling RAG security today?
Most teams reuse controls from search and document management:
- Single sign-on in front of the assistant.
- Indexing "only internal sources", on the assumption that internal means trusted.
- Filtering results or citations against the user's permissions after retrieval.
- Periodic syncs of access control lists into the index, sometimes weekly.
- A system prompt telling the model to answer only from provided context.
What do current approaches miss?
- Filtering after search is too late. At Kestrel the filter ran on citations, not on context. Even when teams filter the chunks before the model sees them, a post-filter over a top-k list can return empty or skewed results, and OWASP notes that result counts, scores and timing can leak information across tenants.
- Stale permissions. If access lists are synced weekly, a document restricted on Monday stays visible until the next sync.
- Internal is not the same as trusted. Wikis, ticket systems and shared drives have many editors. One edit can change what the assistant tells everyone.
- No provenance. Without source, author and ingestion time on every chunk, the team cannot find which answers were influenced by a bad document or clean up afterward.
- Deletion does not cascade. Removing a page from the wiki does not always remove its chunks and embeddings from the index.
How do you secure a RAG pipeline?
Apply source permissions during retrieval
Store each chunk with the access attributes of its source document (groups, tenant, classification), keep them in sync with the source system, and put the user's entitlements inside the search query itself:
results = index.search(
vector=embed(question),
top_k=8,
filter={
"tenant_id": session.tenant_id, # from the session, not the client
"allowed_groups": {"any_of": session.user_groups},
"classification": {"not_in": ["restricted"]}, # unless explicitly entitled
},
)
For highly sensitive collections, use a separate index that only entitled users can query at all. Re-check permissions against the source system when a document is opened from a citation, and sync permission changes quickly, ideally on change events rather than on a schedule.
Track document provenance
Record for every chunk its source system, document ID, version, last editor, ingestion time and trust tier. OWASP recommends provenance for every embedding. Provenance lets you show users where an answer came from, weight or exclude low-trust sources, and find every affected answer when a document turns out to be bad.
Screen, review and remove suspicious content
At ingestion, normalize text (for example, strip zero-width characters), flag content that looks like instructions to an AI, and route high-impact changes, such as edits to policy, finance or security pages, for review before they are indexed. Keep content from different trust levels in separate indexes. When something suspicious is found, remove the chunks and embeddings, re-index from a clean version, and use provenance logs to identify answers that may have relied on it. The OWASP Data and Model Poisoning entry adds version control of data for rollback and forensic analysis.

Recommendations
- Move permission checks into the retrieval query and stop relying on citation or result post-filters. Owner: platform team.
- Sync access changes from source systems on change events, and re-check permissions when a cited document is opened.
- Separate indexes by sensitivity and trust tier, with restricted collections queryable only by entitled users. Owner: data owners with the platform team.
- Record provenance on every chunk: source, document ID, version, editor, ingestion time and trust tier.
- Review edits to high-impact sources such as policy, finance and security pages before they reach the index. Owner: content owners.
- Screen content at ingestion for hidden text and instruction-like passages, and quarantine rather than silently index them.
- Make deletion cascade from source documents to chunks, embeddings and caches, and test it.
- Test with two accounts and planted documents: check that a restricted document never reaches the model for an unentitled user, and that a planted false policy is caught or traceable. Owner: AppSec.
How does this map to OWASP, NIST and the EU AI Act?
In the OWASP Top 10 for LLM Applications 2026, RAG security sits mainly under LLM09:2026 Vector and Embedding Weaknesses (access control, provenance, poisoning at retrieval) and LLM05:2026 Data and Model Poisoning (corrupted corpora). LLM01:2026 Prompt Injection covers instructions delivered in retrieved content, and LLM02:2026 Sensitive Information Disclosure covers what leaks. LLM07:2026 Misinformation is relevant when poisoned content produces confident but false answers.
The NIST Generative AI Profile (NIST AI 600-1) covers related risks, including information integrity, information security and data privacy. NIST's adversarial machine learning taxonomy (AI 100-2 E2025) classifies poisoning and privacy attacks and is useful vocabulary for threat models. For high-risk systems, Article 15 of the EU AI Act includes cybersecurity requirements that name data poisoning among the AI-specific vulnerabilities to address.
Where can you discuss and learn more?
- The OWASP LLM Top 10 GitHub discussions are open for questions and proposals on the 2026 entries, including LLM09.
- Working channels for each risk run on OWASP Slack; the GenAI Security Project contribution page explains how to join.
For implementation detail on the retrieval side, see our guides to building a reranker for search and RAG and semantic search with embeddings. Acta builds AI features on meeting data and takes these questions seriously; see our security page.
Frequently asked questions
Is filtering results after vector search ever acceptable?
As an extra check, yes. As the only control, no. Filtering inside the query means restricted content never enters the candidate set, which avoids both leaks into the model's context and side channels from scores or counts.
How do we know if a document has been poisoned?
Often you will not know immediately. Provenance, review of high-impact edits, instruction-like content detection and monitoring for sudden changes in answers to common questions give you early signals and a way to trace impact.
Do we need to re-index when permissions change?
You need to update the permission attributes on affected chunks, not re-embed the text. Event-driven syncs keep this fast; scheduled batch syncs leave windows where access is wrong.
Does reranking reduce poisoning risk?
Not on its own. A reranker improves relevance, and a well-crafted poisoned passage is designed to look relevant. Use source trust and provenance as signals alongside relevance.
Related in this series: AI data leakage and what existing controls catch and miss.
Found this useful? Like it, share it or follow the blog.


