AI Systems · Architecture

Permissioned Retrieval Systems

ACL-aware RAG architecture: query-time permission filtering, IdP groups, no existence leak, audit, failure modes, evals, and why index-time ACL is not enough.

Read time
16 min
Level
Advanced
Updated
2026-08-25
Components
IdP token resolver · Document ACL index · Query-time filter
The short answer

A permissioned retrieval system resolves the asking user’s live entitlements from an identity provider, applies those ACLs at query time so unauthorized chunks never enter the retriever’s result set or the model context, and is designed so that empty results, rankings, timings, and citations do not reveal that a forbidden document exists. Index-time ACL snapshots go stale; post-generation filtering is a leak — the model already saw the text.

Key takeaways

  • 01

    Filter at query time against live IdP groups and document ACLs; baking permissions into the index as the only control goes stale the hour access changes.

  • 02

    Unauthorized text must never reach the embedding search shortlist, the re-ranker, or the prompt — post-filtering after generation is already a confidentiality failure.

  • 03

    No existence leak: same empty-result behavior, no “you don’t have access to X,” no citation or count that implies a hidden hit, no timing oracle.

  • 04

    Service-account indexes that retrieve everything and then filter in the app are how agents leak restricted wikis in week two.

  • 05

    Evaluate with paired users on the same query: authorized hit vs uniform miss, plus citation and log audits for forbidden doc ids.

01

Why RAG without query-time ACL is a leak

Enterprise corpora are not public web pages. The same query from two employees should return two neighborhoods of the graph or the index. A single service account that can read the whole wiki, ticket system, and shared drive will retrieve the compensation memo, the unreleased filing, and the other tenant’s case file, then ask the model to “be careful.” The model is not an access-control layer. Once a chunk is in the prompt, the secret has left the store — it will appear in the answer, the trace, the judge, or the cache.

Permissioned retrieval makes authorization a retriever concern. The generator is only allowed to see passages the user could open in the source application today, with their current groups, not last quarter’s index-time snapshot.

02

Data flow: identity, filter, retrieve, cite

The request carries a user token (OIDC/SAML session, not an API key shared by the app). A resolver talks to the IdP or a group cache and produces a set of principal ids: user, groups, workspace roles, maybe share-link tokens. Those principals are the filter predicate. Dense and sparse retrieval, and graph traversal if you have it, run with that predicate pushed into the index — ACL fields on each chunk, row-level security, or a posting list of principals. The re-ranker sees only authorized candidates. Citations include URLs the same user can open. Traces store chunk ids under access control; a support engineer with a broader role uses their own identity, not the caller’s, if they need to debug.

Ingest still stores ACL metadata on every chunk: owner, ACL version, principals, link-sharing flags, tenant. When the source system emits a permission change, the ACL index updates without waiting for a full re-embed. Re-embedding on every share-toggle is too slow; permission bits must be independently mutable.

  • User token → live principals from IdP (with short TTL cache)
  • Push principal predicate into vector and BM25 indexes
  • Rank and re-rank only inside the authorized set
  • Cite only URLs the user can open; refuse on empty retrieval
  • ACL fields update on permission events, not only on re-ingest
03

No existence leak

Access control that returns “forbidden: Q3-M&A-strategy.pdf” has already confirmed the file exists, its title, and often its path. Search that returns “3 results you cannot open” does the same. A hit count, a facet, a graph neighbor, or a different latency when the unauthorized document is in the corpus are all oracles. The authorized-empty and unauthorized-hidden cases must be indistinguishable to the caller: the same refusal text, the same timing class, no leftover ids in logs the user can see.

Caches are oracles too. Do not key a semantic cache on query text alone; include a principal-set hash so user A’s authorized answer is never served to user B. Prefix caches on the inference server that hold another tenant’s RAG context are a cross-tenant leak. Judges and online evals that log full prompts need the same ACL as the product, or the eval store becomes the well-read shadow copy of the secrets.

04

IdP integration and ACL modeling

Model principals the way the source apps do: users, groups, nested groups, domain-wide claims, and per-document shares. Flatten nested groups at query time or maintain a materialized principal expansion with a TTL you can defend. Break-glass and admin roles are explicit principals, not “skip the filter.” Tokens expire; a long-lived group cache is how offboarded employees keep retrieving until Monday.

Multi-tenant systems add a tenant id that is not optional and is not taken from the query string. Cross-tenant retrieval is a Sev-1 even if the document ACL later would have denied it. For GraphRAG, filter nodes and edges by evidence-document ACL; a community summary must not contain facts whose only evidence the user cannot read — otherwise global search is a summary-shaped leak.

05

Failure modes

Index-time ACL only: a user loses a group and still retrieves the doc until re-index. Retrieve-then-filter on a small k: the authorized relevant chunk never entered the top-k. Post-generation filtering: the model paraphrases the secret without quoting it. Shared semantic cache across users. Debug traces in a ticket that include another employee’s chunks. Embedding a document before its ACL is known, defaulting to public. Graph summaries built without permission context. Timing differences on filtered vs unfiltered queries.

The failure users report is “the agent knew something I don’t have in the UI.” Treat that as an incident, not a hallucination ticket. The failure security reports is “the agent told me a file existed.” Same queue.

  • Stale index-time permissions after group change or offboarding
  • Top-k retrieved without ACL, then filtered to empty
  • Model saw the chunk; output filter cannot un-see it
  • Caches and traces keyed without principal hashes
  • Existence leaks via titles, counts, timings, or graph neighbors
06

Evals, and when not to use this design

Build paired cases: the same query as user A (should hit document D) and user B (must not). Report authorized hit@k, unauthorized leak rate (any forbidden chunk id in retrieval, prompt, answer, citation, or user-visible log), and existence-oracle tests (can B distinguish D’s presence). Include nested-group, expired-share, and tenant-isolation slices. Run these in CI on retriever changes. Online: sample traces and scan for chunk ids outside the caller’s principal set.

You still need this design if the corpus has any ACL at all. The “when not” is narrower: a truly public knowledge base with one tenant and no employee-only docs can skip principal expansion — and should still isolate caches per environment. Do not “simplify” by retrieving as a superuser for an internal agent that Slack-broadcasts answers. If you cannot connect the IdP, do not index the restricted sources; a smaller permissioned corpus beats a clever leak.

Frequently asked questions

What is permissioned retrieval?

Permissioned retrieval resolves the asking user’s live entitlements from an identity provider and applies those ACLs at query time so unauthorized chunks never enter retrieval, re-ranking, or the model prompt. Citations point only at URLs that user can open. It also hides existence: no titles, counts, or errors that confirm a forbidden document is in the index. The generator is not the access-control layer.

Why not store ACLs only at index time?

Index-time ACL snapshots go stale when someone is added to or removed from a group, a share link expires, or an employee is offboarded. Re-embedding the corpus on every permission change is too slow. Store ACL principals as mutable metadata, update them on source events, and evaluate the live IdP groups at query time. Index-time bits can speed the filter; they cannot be the only control.

What is an existence leak in RAG?

An existence leak is any signal that tells a user a document they cannot read is in the system: “access denied” with a title, a hidden-hit count, a facet, a graph neighbor, a distinctive error, or a slower response when the forbidden file matches. Authorized-empty and unauthorized-hidden must look the same. Caches keyed only on the query text leak across users in the same way.

Why is filtering after generation too late?

Once the chunk is in the prompt, the model can paraphrase the secret, put it in a tool argument, or leave it in a trace the user or an operator will see. Output classifiers miss paraphrases. Retrieve with the ACL predicate pushed into the indexes so forbidden text never ranks, never re-ranks, and never reaches the context window. Post-filters are defense-in-depth for accidents, not the control.

How do you evaluate ACL-aware RAG?

Use paired identities on the same query: the authorized user must retrieve the gold chunk; the unauthorized user must see a uniform miss with no forbidden ids in retrieval, prompt, answer, citations, or user-visible logs. Add nested-group, expired-share, and tenant-isolation cases. Scan production traces for chunk ids outside the caller’s principals. Leak rate is a hard CI gate, not a quality dashboard widget.

Keep reading

ArchitectureMulti-Agent Orchestration SystemsQualityLLM Evaluation Systems (Evals)TrainingRL Environments for Agent TrainingArchitectureAgent Memory SystemsArchitectureAgentic RAG SystemsArchitectureComputer-Use Agent SystemsArchitectureFunction-Calling and Tool-Use SystemsArchitectureGraphRAG SystemsArchitectureHuman-in-the-Loop AI SystemsArchitectureHybrid Retrieval and Re-ranking SystemsQualityLLM Guardrail SystemsInfrastructureLLM Inference and Serving SystemsInfrastructureLLM Observability and TracingInfrastructureMCP Tool Gateway SystemsArchitectureModel Routing and Fallback SystemsTrainingPEFT and Fine-Tuning PipelinesQualityPrompt Injection Defense SystemsArchitectureRAG ArchitectureArchitectureRealtime Voice AI SystemsQualityAI Red-Teaming SystemsArchitectureStructured Generation SystemsTrainingSynthetic Data Generation Systems

Building one of these systems?

We help teams design, build, and validate production AI systems — orchestration, evals, and training environments included.

FAQ

Working with us

How soon can AI systems work start?

Typically within a week or two of a scope being agreed. The first delivery is deliberately a small batch so you can check the output against your expectations before volume ramps.

What do you need from our team?

One process owner who knows the workflow, one engineer with access to the systems involved, and a weekly 45-minute review. No standing committee, and no requirement for an ML specialist on your side.

Who owns the output and the data?

You do. Datasets, labels, weights, evaluation suites and runbooks are yours and are handed over at the end. Your data trains your models only, with zero-retention provider settings by default.

Can you scale volume up quickly if we need it?

Yes, and the quality bar holds because the rubric and gold set are already agreed by that point. Ramping is a staffing question, not a re-scoping one, so it usually takes days rather than a new engagement.

We already have a vendor for this. Why switch?

Often you should not. The cases where teams move to us are when they cannot get a quality number out of their current vendor, or when the work is delivered as an opaque batch with no trace of how disagreements were resolved.

What happens after the engagement ends?

We stay on-call for 30 days at no extra cost, then move to an optional support retainer. Most teams also keep a quarterly evaluation review with us to catch drift early.

Copyright © 2026
ReinforcedX, Inc.
All rights reserved