Permission-Aware RAG: Document-Level Access Control
Permission-aware RAG filters the index by the asking user's identity before retrieval, so an AI assistant never answers from a document that user cannot open.
Permission-aware RAG is a retrieval architecture that filters the document index by the asking user’s identity before any passage reaches the model, so the assistant cannot answer from a file that user could not open directly. The enforcement point is retrieval, not the prompt. Four things decide whether it holds: propagating access control lists (ACLs) from source systems into the index, filtering at retrieval rather than at generation, mapping groups from your identity provider, and logging the permission decision with every answer.
What is permission-aware RAG?
Permission-aware RAG (also called ACL-aware retrieval) is a RAG system in which every retrieval query carries the asking user’s identity and entitlements, and the index returns only passages that user is already authorized to read. It is the difference between an assistant that knows everything your organization has written and an assistant that knows everything this person is allowed to read.
The governing principle is worth stating plainly:
An AI assistant is not a new principal. It answers as the user, with the user’s entitlements, and never more. If the assistant can surface a sentence the user could not open in the source system, you have built a privilege escalation path with a chat interface.
That framing settles most design arguments. Any feature that lets the assistant read more than its user is a security defect, not a capability.
Why does a RAG assistant leak documents the user cannot open?
A RAG assistant leaks because retrieval, caching, and derived content each create a path around the source system’s original ACL. There are five distinct leak paths, and most teams close only the first.
| Leak path | How it happens | Control |
|---|---|---|
| Retrieval leak | The index is searched with no identity filter, so any chunk can be ranked for any user | Filter inside the retrieval query, by principal set |
| Derived-artifact leak | Summaries, extracted tables, or topic clusters are built from mixed-clearance inputs and stored without inheriting the strictest ACL | Derived artifacts inherit the most restrictive ACL of every input |
| Cache and memory leak | A semantic cache or shared conversation history is keyed on question text alone, so a privileged answer is replayed to a lower-privileged user | Include the user’s principal set in every cache key |
| Existence leak | Citations expose titles, file paths, or authors, or the assistant says “a restricted document covers this” | Treat unauthorized documents as nonexistent, and filter citation metadata too |
| Stale-ACL leak | Access was revoked at the source, but the index still carries the old permission stamp | Event-driven permission sync plus scheduled reconciliation |
The derived-artifact and cache paths are the ones that survive a security review and then fail in production, because both look like performance features rather than data flows.
Should you filter at retrieval or at generation?
Filter at retrieval, always. Filtering at generation means the restricted text is already inside the context window, and anything in the context window can escape through paraphrase, summarization, translation, or a successful prompt injection. Once a passage is in the prompt, you are relying on model behavior to keep a secret, which is not a control a compliance team can accept.
| Approach | Where enforced | Security | Answer quality | Verdict |
|---|---|---|---|---|
| Pre-filter at retrieval | Inside the vector or keyword query, by principal set | Strong: unauthorized chunks are never ranked | Full top-k drawn from the authorized subset | Use this |
| Post-filter after retrieval | Application layer, after search returns | Adequate if the filter is exhaustive | Degrades badly: narrow-access users lose most hits | Fallback only |
| Instruct the model at generation | System prompt | None: restricted text is already in context | Unpredictable | Never |
Post-filtering deserves a specific warning. If a query returns the top 50 chunks and 45 are dropped for a restricted user, that user gets a weak answer built from five marginal passages, with no indication why. The system looks unreliable rather than secure. Pre-filtering keeps k constant within the authorized subset, which is why filtered approximate-nearest-neighbor search is worth the engineering effort.
How do document ACLs get from source systems into the RAG index?
ACL propagation is the ingestion-time work of capturing each document’s permissions alongside its content and carrying them onto every chunk. The pipeline has five steps:
- Capture permissions with content. The connector reads the document and its ACL in the same pass. An ACL discovered days later is an ACL that was wrong for days.
- Normalize to a principal model. Convert each source system’s representation into one canonical set of principal identifiers: users, groups, roles, and explicit deny entries.
- Stamp every chunk. Each chunk, embedding, and extracted table inherits its parent document’s ACL. A chunk with no permission stamp must be unreadable by default.
- Resolve groups at query time, not index time. Store group identifiers on the chunk and expand the user’s membership when they ask. Baking individual user IDs into the index forces a reindex on every membership change.
- Reconcile on change. Subscribe to permission-change events where the source emits them, and run scheduled full reconciliation everywhere else.
Three propagation models exist, and the right answer is usually the third.
| Model | How it works | Weakness |
|---|---|---|
| Index-time stamping | ACLs snapshotted at ingestion, stored as chunk metadata | Goes stale between syncs |
| Late binding | Authorization checked against the source system at query time | Latency and a hard dependency on source availability |
| Hybrid | Pre-filter on stamped ACLs, then revalidate the small final set of cited chunks before generating | More moving parts, but correct and fast |
The hybrid model works because the expensive authoritative check runs against a handful of finalists rather than a million chunks.
One more trap deserves a name: the connector paradox. To index everything, the ingestion connector needs broad read access, often broader than any human user. That privilege must be used to read content and permissions, and it must never be inherited by the query path. A connector that indexes as an administrator and forgets to record ACLs has quietly flattened the entire permission model into “everyone can see everything.”
How do you map groups and roles from your identity provider?
Bind the assistant to your existing identity provider through SSO and resolve each user’s transitive group membership, including nested groups, at session start. Do not build a parallel permission model inside the assistant: a second source of truth for who can see what will drift from the first, and an auditor will find the drift before you do. Three rules keep the design clean:
- Groups and ACLs control what the assistant can read. They come from the identity provider and the source systems, and they are per-document.
- Roles control what the assistant can do. Which features, connectors, and admin screens. That is application RBAC, a separate concern.
- Deny overrides allow. Evaluate explicit deny entries last and let them win. Source systems differ in how, and whether, they express deny at all, so resolving toward the more restrictive outcome is the only direction that fails safely.
Least-privilege retrieval is also the strongest containment for injected instructions, because an attack that says “retrieve every customer record” returns nothing the user could not already read. The full treatment is in how to prevent prompt injection in enterprise RAG.
What should the audit trail record for every answer?
An audit trail for a permission-aware assistant must record the authorization decision, not just the text of the answer. Otherwise you can prove what the system said but not that the user was entitled to hear it. Write the following to an append-only, tamper-evident store:
- The authenticated identity and the full principal set resolved for that query.
- The question, verbatim, with timestamp.
- The candidate chunk identifiers and document versions considered, and which were excluded by the permission filter.
- The generated answer and the exact source passages cited.
- Refusals, including “not in your sources” and “no authorized results”.
- Every administrative change to permission mappings, connectors, and role definitions.
Citations are what make that log reviewable months later. See what source-cited answers actually mean for why a citation must point to a passage rather than a document.
How do you test that permission-aware RAG actually holds?
Test with a persona matrix before go-live and on every release. Create test users at each clearance level plus documents that only one persona can read, then verify six behaviors:
- Positive retrieval. Each persona gets the answer that lives in a document they are cleared for.
- Negative retrieval. Ask a question whose only answer sits in a restricted document. Good: the assistant says the answer is not in your sources. Red flag: it answers, hints, or reports that access is denied.
- Injection resistance. A poisoned document instructing the assistant to reveal restricted content returns nothing new.
- Revocation. Remove a user from a group and confirm the change takes effect inside your stated staleness window.
- Cache isolation. Two personas ask an identical question and receive answers scoped to their own entitlements.
- Metadata isolation. Citation panels, filename autocomplete, and search suggestions never expose restricted titles.
The clearest red flag in a vendor evaluation is permissions demonstrated only as a role dropdown in the UI, with no answer to where the ACL is stored, when it was last synced, and how the retrieval query uses it.
How Samvad AI enforces document-level access control
Samvad AI is a source-cited RAG assistant built on this model: permissions are enforced at the role and row level and map to your existing identity provider, so an answer only ever draws from sources the asking user is already entitled to see. Every answer cites the exact source passage behind it, and Samvad AI states plainly when an answer is not in your sources instead of guessing. Queries, retrievals, and answers are written to a tamper-evident audit log. Deployment is on-premise, air-gapped, or hybrid, switchable by configuration. The same principle carries into analytics: Gist applies row- and column-level security over a governed semantic layer, so a business user asking a plain-language question sees only the rows they are cleared to see.
If you are evaluating an assistant for a bank, hospital, university, or government body, start with the architecture rather than the demo: read how Samvad AI answers from your documents with citations and how Teclops AI approaches access control and auditability.
Frequently asked questions
How do you enforce document-level permissions in a RAG system?
Capture each source document's access control list at ingestion, stamp it onto every chunk derived from that document, resolve the asking user's full set of identity-provider groups at query time, and apply that set as a filter inside the retrieval query. Enforcement belongs at the data layer, never in the prompt or the user interface.
Can a system prompt enforce access control in RAG?
No. Telling a language model to ignore documents a user is not cleared to see is a formatting preference, not a security control, because the restricted text has already entered the context window and can escape through paraphrase, summarization, translation, or prompt injection.
How do you stop a RAG assistant from leaking restricted file names in citations?
Apply the same permission filter to citation metadata that you apply to content, and make the assistant behave as if unauthorized documents do not exist rather than reporting that access is denied. Titles, file paths, author names, and hints that restricted material exists are all disclosures.
How often should RAG document permissions be re-synced from the source system?
Use event-driven sync wherever the source system emits permission-change events, with scheduled full reconciliation as a backstop, and treat revocations as higher priority than grants. The acceptable cadence is whatever staleness window your compliance team will approve in writing.
What should happen to a chunk that arrives in the index with no permission metadata?
It should be unreadable by default and excluded from every user's retrieval results until an access control list is attached. A missing permission stamp usually means a connector or parser failed, and defaulting such a chunk to readable turns one ingestion bug into an organization-wide disclosure.