Permission-Aware Retrieval for Enterprise RAG
Engineering

Permission-Aware Retrieval for Enterprise RAG

The model should never receive a passage that the requesting user is not allowed to read. Here is where to enforce that, what to store, and how to test it.

Short answer

Permission-aware retrieval means a RAG system only retrieves passages the person asking may read in the source system. Enforce it as a filter inside the search, not in the model's instructions: store the permitted users and groups with every passage, match them against the user's current groups at query time, and keep anything that does not match out of ranking altogether.

What is permission-aware retrieval and why does it matter?

An enterprise RAG system pulls files from shared drives, support tickets, wiki pages and contract archives into one search index. In the source systems, every document has an access control list (ACL) that says who may read it. If that list is lost during ingestion, the index becomes a single pool where everyone can reach everything. A user can ask a question that sits entirely within their own permissions, and retrieval will still return the semantically closest passage, which may be a salary table meant only for managers.

Permission-aware retrieval means search returns only passages the person asking is allowed to read in the source system. The risk is not limited to a citation in the answer: once the model sees a restricted passage in its context, it can summarise it, paraphrase it or use it in the next tool call. OWASP's 2025 list of risks for large language model applications treats this as its own category: its vector and embedding weaknesses entry includes one group's documents being retrieved for another group's query and context leaking across tenants. The same entry notes that significant parts of the source text can be recovered from embedding vectors, so the vector store needs at least the same protection as the document store.

Where should permissions be enforced?

There are four places to enforce permissions, and they do not give the same guarantee. The most common mistake is leaving the check to the very end, as an instruction to the model.

MethodWhen it fitsWatch out for
Security filter at query timeThe default for most enterprise RAGEvery passage needs a current permission field
Separate index per tenant or groupA small number of strictly separated customers or unitsCost and maintenance grow with the number of groups
Checking results against the source systemPermissions change very often and extra latency is acceptableLatency and API limits; use with a filter, not alone
Dropping results after search, before the modelA stopgap until a filter is in placeAnswer quality falls as results are removed
Telling the model not to use restricted contentNever on its ownThe model has already seen the restricted text

We recommend enforcing permissions in the search itself, as a filter, before ranking and generation. Microsoft describes this for Azure AI Search as the security filter pattern: each document has a field holding the permitted group IDs, and the query adds a filter on that field with the user's groups. In Elasticsearch, the same job is done with document-level security, a query written into the role definition that can reference the signed-in user through a template.

What permission data belongs in the index?

For the filter to work, store at least these fields with every passage:

  • Source document ID: Which document and which version the passage came from.
  • Tenant: In a multi-customer product, the customer the passage belongs to; a mandatory filter on every query.
  • Permitted users and groups: Stable identifiers rather than values that can change, such as email addresses. Azure AI Search's document-level access feature also asks for Microsoft Entra object IDs in its user and group fields.
  • Where the permission comes from: Inherited from a folder, granted on the document, or opened through a sharing link.
  • Sync time and ACL version: So you can measure how stale this information is.
  • Sensitivity label: Classes such as "confidential" or "contains personal data", if you have them.

Check how mature the built-in options are, too. At the time this article was updated, Azure AI Search's document-level access features (ADLS Gen2 ACLs, SharePoint permissions, Microsoft Purview sensitivity labels) are still in preview. Preview features are not covered by a service-level agreement and Microsoft does not recommend them for production workloads. According to the same page, attribute-based (ABAC) conditions in ADLS Gen2 are not evaluated, and permission changes take some time to reach search. Whichever route you choose, test its behaviour with your own data before going to production.

Inheritance, exceptions and revocation

Write down a rule for how folder permissions, sharing links, document-level exceptions and group membership carry over to passages. A file can override its folder's rule, in which case a group label inherited only from the folder is wrong. Nested groups are often missed as well: a user may be authorised not directly but through a subgroup.

Set a target time for revocation and measure it. For example, when an employee is removed from the HR group, you might aim for payroll documents to disappear from search within 15 minutes. What matters is not the number itself but that it matches expectations in the source system and is monitored. Raise an alert when sync falls behind; hiding documents whose ACL data is older than the agreed limit is safer than showing them to the wrong person.

Example: the payroll query test

An employee asks, "How is this year's pay rise calculated?" The index holds two documents: the public pay policy and a managers-only table with individual rise percentages. The table may be semantically closer to the question. Ask the same question under three identities and check the raw search results, the list of passages before anything reaches the model:

IdentityShould seeShould not see
EmployeePay policyRise table
HR specialistPolicy and tableAnother tenant's documents
Specialist just removed from HRPay policyRise table (after the target time)

Inspect the raw result IDs and passages, not only the final answer. The model may have seen the restricted passage and still written a harmless answer; that does not mean the test passed.

A leakage test plan

Automate the following tests and run them after every connector, group sync or index change:

  1. Ask the same question under identities with different permissions and compare the raw results.
  2. Remove a user from a group and repeat the test once the target time has passed.
  3. Create documents with the same name for two tenants; no result may cross between them.
  4. Ask for the restricted information indirectly rather than by name ("last year's rise range for managers").
  5. Check how files shared by link, or shared outside the company, are indexed.
  6. Add a document with missing ACL data; search must never return it.
  7. Test cached answers under different identities.
  8. Open the citation link in an answer as an unauthorised user; the source system must deny access.

Separate the ingestion pipeline and identities

Connectors may need broad read access to fetch source files; that access must never pass to the user running the query. Use separate service identities for ingestion and for queries, and record where every passage came from. OWASP's AI agent security cheat sheet stresses least privilege and treating retrieved content as untrusted data. The same principle makes it harder for a malicious document to steer later tool calls.

Caching, citations and logs

An answer cache cuts cost but can easily break the permission boundary: an answer generated for a manager's question can be served from cache to an employee who asks the same thing. Add the tenant and the user's permission set to the cache key, or switch caching off for permission-sensitive queries. Citation links must go through the source system's own access check. In the audit log, keep the user ID, the filter applied, the returned document IDs, the ACL version and the time, without storing sensitive text you don't need. If permissions cannot be evaluated, return a safe error instead of widening the search.

Common mistakes

  • Hiding restricted results only in the interface, not enforcing permissions in search.
  • Ingesting permissions once and never syncing group changes.
  • Using values that can change, such as email addresses, as identifiers.
  • Testing only the final answer and never looking at the raw results.
  • Leaving caches and summary indexes outside the permission model.

How Hatson Tech builds this

Permission filters applied at retrieval time are a basic requirement in our RAG and semantic search solutions. We start a project by mapping the permission model of the source systems and write the test plan above into the acceptance criteria. Where data cannot leave the organisation, see our guide to in-house AI; to improve search quality, see our article on hybrid search and reranking. Before applying this approach, check the sources against your own data, permissions and the product versions you use.

Key takeaways

  • Filter passages by the caller's effective permission inside the search, before ranking and generation.
  • Store stable user and group IDs, the permission source and the sync time with every passage.
  • Set a revocation target, alert on stale ACL data and hide documents whose permissions are unknown.
  • Test raw results, not only the final answer, under several identities and tenants.
  • Bring caches, citations and audit logs inside the same permission boundary.

Frequently asked questions

Can I enforce RAG permissions by instructing the model?

No. By the time the model reads the instruction, the restricted passage is already in its context and can surface in a summary, a paraphrase or a tool call. Permissions have to be enforced in the search, before ranking and generation.

Do vector databases handle access control themselves?

Many offer metadata filters, namespaces or document-level security, but they can only enforce what you give them. Your application has to store the permission fields with each passage and pass the signed-in user's identity and groups with every query.

How quickly should RAG reflect a removed permission?

As quickly as the source system's own expectations require. Set a target time, measure it after every group sync, and hide documents whose permission data is older than the agreed limit.

Are embeddings sensitive data too?

Yes. OWASP notes that significant parts of the source text can be recovered from embedding vectors, so the vector store needs the same access control, encryption and retention rules as the documents.

Should a multi-tenant product use one index or one per tenant?

With a few strictly separated customers, separate indexes give the strongest isolation. With many tenants, a shared index with a mandatory tenant filter on every query is usually more practical, provided cross-tenant tests run automatically.

All articles