Skip to main content
Back to all essays
System Design7 min read

RAG document permissions: test revocation and cached answers

A worked enterprise search example explains security filters, permission synchronization, chunk metadata and the caches that can leak restricted answers.

Permission-aware retrieval separates tenant A's allowed documents from tenant B's restricted documents before model context. A revocation timeline shows why stale ACL metadata and cached answers need an explicit policy.
Open full-size workflow diagram
Read the workflow steps
  1. Authenticate the reader and derive tenant and access scope on the server. The prompt cannot select broader permissions.
  2. Retrieve only eligible chunks and their citations. Apply permission enforcement before evidence reaches the model, including reranking and cache paths.
  3. At 10:00 in the fictional example, document access is revoked. The index still has ACL version 18 until synchronization at 10:05.
  4. Use the application's stated revocation policy: check current authority or hold during uncertainty, refresh all chunks, and prevent replay of a cached restricted answer. These example times are not a vendor guarantee.
Cover graphic for RAG document permissions: test revocation and cached answers, System Design

A RAG assistant can cite the right document and disclose it to the wrong employee. Search relevance measures how well a passage answers the question. Document permission determines whether this reader may receive that passage at all. Both have to hold before the assistant produces an answer.

This article works through a fictional insurance operations search. It focuses on read access, revoked permissions and answer caches. The examples are proposed designs and acceptance cases, not findings from a customer system. Write permissions and instructions embedded in documents are separate concerns covered in our document-agent article. Read: document data and action permissions

Define what the reader may retrieve

Our fictional application serves two tenants. Reader P-7 works in tenant A and can read that tenant's general claims handbook. A restricted carrier agreement belongs to tenant B. Both documents mention the same policy exception, so a search without access filtering could rank the tenant B agreement highly. The answer must use tenant A's permitted evidence, even if the other agreement looks more relevant.

I would authenticate P-7, derive tenant membership on the server and resolve the permitted source scope there. The browser's request and the user's prompt can carry a question, but neither can supply authoritative group membership. 'Search all tenants' should not broaden P-7's access. The server must also check identity again on a later turn rather than treating an old conversation as a standing permission grant.

Illustrative retrieval contract, not a provider request
reader: P-7  # derived from authenticated session
tenant: A    # derived by server authorization
question: Which exception rule applies?
source_scope: claims-handbook
required_permission: read
permission_state: current
unauthorized_evidence_sent_to_model: none

Choose the permission mechanism explicitly

Azure AI Search documents both security filters and native identity-based document permissions. The filter pattern compares stored principal strings; it does not authenticate those strings. Native ACL, RBAC-scope and sensitivity-label approaches have source-specific requirements and are marked preview in the current overview. The preview caveats matter when selecting a production design. Microsoft: document-level access approaches

For application-managed filters, the service behind the assistant must derive and apply the access predicate to every relevant query path. Microsoft describes storing principal identifiers in a filterable field and using search.in to trim matches. Making a permissions field non-retrievable does not protect document content by itself. Microsoft: security filter pattern and its limits

Two implementation choices to review
ChoiceResponsibilityCheck before rollout
Application-managed access filtersApplication authenticates the caller and builds mandatory filtersEvery search, chunk lookup, reranking and cache path uses the permitted scope
Native identity-based permissionsSearch service evaluates the supplied identity against indexed permission metadataSupported source/API, preview constraints, token handling and metadata synchronization

Neither choice makes a search index the live source of every permission change. The team should document where authority comes from, how it reaches the index, and what the application does when it cannot establish that the copy is current. Choose that contract before advertising a revocation guarantee.

Enforce access before model context

In the proposed system, eligible candidates are selected before their text reaches the model or a downstream reranking service. A final instruction telling the model to hide tenant B's agreement arrives too late if the agreement is already in the context. The same review should cover citation titles, direct document lookups and diagnostic traces. An inaccessible document's title can itself disclose information.

Filter placement also affects retrieval quality. Azure distinguishes preFilter, postFilter and preview strictPostFilter for vector queries. Restrictive postfilters can miss eligible matches because they trim a previously selected candidate set. I would measure recall within the allowed document set, alongside the permission checks, rather than remove filtering to improve an answer. Microsoft: vector filtering modes and recall

Chunking creates another place to lose scope. Suppose the handbook becomes 40 passage records. Our design gives every passage its parent ID and applicable access metadata. The lookup used to display a citation checks access too. A secure first search followed by an unrestricted fetch-by-ID would still let a reader recover a forbidden passage.

Walk a permission revocation through the system

At 09:55 in the fictional example, P-7 can read document D-42 under ACL version 18. At 10:00, its owner removes that access. The search index does not receive ACL version 19 until 10:05. These times illustrate a synchronization gap; they are not an Azure latency commitment.

Microsoft states that query-time enforcement uses permission metadata already synchronized into the index. Source changes reach results after the source-specific update mechanism runs. Its SharePoint guidance distinguishes incremental handling of certain item permissions from changes inherited from parent scopes that require an explicit refresh. Microsoft: SharePoint permission synchronization

If the business requires P-7's next request after 10:00 to be denied, an index-only check against version 18 cannot meet that rule. I would evaluate a fresh source authorization check or an application revocation signal that blocks affected reads until synchronization is proven. If the source cannot support the required check, the team needs a stated delay bound or a stricter hold policy. That is an engineering contract to test, not a promise inferred from the word 'permission-aware'.

Verify every child passage after refresh, including deleted and renamed documents. A partially updated index can leave an old chunk accessible even when the parent record looks correct. If the permission service fails, the proposed restricted search returns an unavailable status rather than retrying without its filter. That failure should have an owner and a recovery path.

An answer cache needs its own access decision

Imagine the assistant answered P-7 at 09:55 and cached the response by question text. At 10:01, it could return the same answer without searching again, bypassing the fresh authorization path. I would bind reusable answers to tenant, effective read scope and source versions, retain the cited document IDs, and reauthorize those dependencies before replay. If authority cannot be checked, recompute or hold.

A scope-aware cache key helps separate users but does not prove that a document remains readable after revocation. It needs invalidation or a fresh check. The same rule applies to conversation memory and summaries reused as grounding evidence. Previously delivered text cannot be made unseen; the design should distinguish historical records from new retrieval and new disclosure. Define who may reopen saved conversations as well as who may run a new search.

Test forbidden evidence, not just the final wording

Proposed tests for the fictional permission-aware search
CaseExpected resultInspect
Tenant B document ranks first for P-7Use only eligible tenant A evidenceRetrieved chunks, reranker inputs and model context
Prompt requests another tenantKeep server-derived scopeAuthorization decision and query predicate
Access revoked; index still at version 18Apply the stated fresh-check or hold policyNo new restricted evidence disclosure
Cached answer cites revoked D-42Deny replay or recompute from permitted sourcesCache dependencies and read checks
One child chunk misses an ACL refreshDetect or deny the inconsistent readAll chunk records, not only the parent
Permission lookup is unavailableFail closed for restricted contentNo fallback query without access enforcement
Allowed evidence exists but ranks below forbidden hitsRetrieve the eligible answerRecall over the permitted corpus

Keep synthetic restricted facts in test documents so engineers can detect a leak without using actual confidential material. Count unauthorized chunks at each processing boundary, incorrect denials, unanswered eligible questions and the observed revocation delay. A final answer that omits a secret can still fail if the secret reached an unauthorized processing stage.

Start with one source whose permission model the team understands. Run the revocation case through search, citations, caches and saved conversations, then repeat it after a worker restart and a partial indexing failure. Expand the corpus only when the business can state what happens to each restricted read during those failures. Retrieval accuracy and access control both belong in the release criteria. Read: retrieval as an application subsystem

Putting this into practice?