Access-controlled retrieval for RAG and agents definition
Access-controlled retrieval is a retrieval design in which the requesting identity's permissions are applied inside the retrieval query itself, so that a RAG pipeline or agent only ever receives passages that identity is authorized to read.
You prevent confidential content from leaking into RAG answers by applying the caller's permissions inside the retrieval query, before any passage reaches the model. In Sanity, a custom role can attach a content resource defined by a GROQ filter such as `identity() in allowedEditors`, so the Content Lake returns only documents that user is permitted to read (custom roles and content resources are an Enterprise plan feature). Filtering later cannot undo a disclosure that already happened.

Why does filtering after retrieval fail to stop leaks?
Filtering after retrieval fails because confidential content has already left the store. In a post-filtering design, the system fetches the top matching chunks and then drops the ones the user is not allowed to see, which means unauthorized passages have already been read, re-ranked or summarized, and written into retrieval logs and traces. The retrieval documentation at unrag.dev states the position bluntly: "Post-filtering is an anti-pattern. Design for pre-filtering instead."
There is a subtler failure too. If a query returns two results where ten matched, the gap itself discloses that eight relevant hidden documents exist. In sensitive contexts, the existence of the content is the disclosure.
Access-controlled retrieval avoids these failures by making the permission check part of the query predicate, not a cleanup step afterward. Content the caller cannot see is never selected in the first place, so there is nothing to filter, nothing to log, and no result-count signal to interpret.
Why aren't output guardrails enough to protect confidential content?
Output guardrails are not enough because they are a detection control, not an authorization control. A classifier that inspects the generated answer and blocks sensitive text only acts after confidential content has entered the model's context window, been processed by a model API that may sit outside your infrastructure, and been written to logs. Access-controlled retrieval is deterministic, while guardrails are probabilistic, and a probabilistic check is a weak last line against a disclosure that already occurred.
The same reasoning rules out prompt instructions. Telling a model "do not reveal HR documents" is advice to a stochastic system, and it can be overridden by prompt injection hidden in retrieved content.
The practical rule is that the context window is the trust boundary. Anything that reaches it has been disclosed, regardless of what the user is shown afterward. The last point at which you can reliably prevent disclosure is the retrieval query. The OWASP RAG Security Cheat Sheet treats output validation as defense in depth and lists access control metadata on every vector chunk among the controls to implement immediately.
What are the building blocks of access-controlled retrieval?
Access-controlled retrieval is built from six pieces that appear consistently across published guidance. First, identity propagation: the end user's identity has to reach the retriever, not stop at the chat interface, usually through OAuth or OIDC token exchange, forwarded session tokens, or signed JWT claims carrying group membership. Second, role-based access control, so permissions resolve from roles, not hand-maintained per-user lists. Third, document-level scoping, meaning per-document access lists, owner fields, or a group-overlap check.
Fourth, field-level scoping, which returns only the permitted fields of an otherwise readable document. This is the building block most RAG stacks skip, and it matters when a document is broadly readable, but a salary or contact field inside it is not. Fifth, metadata filters at query time: a tenant ID, workspace ID, classification label, or permitted-groups array carried on every chunk and used as a filter predicate in the vector or keyword query. Sixth, fail-closed behavior, meaning that a permission check that cannot be answered denies, not falls open. Alibaba Cloud's PolarDB documentation describes the same shape: permission checks in the recall stage, access list propagation, a fail-closed policy, and sanitized content fields.
Where does access-controlled retrieval matter most?
Access-controlled retrieval matters most when one assistant can reach both internal and public content for a mixed audience. Common cases include enterprise agents indexing an entire intranet, Slack and Teams bots that answer for anyone in the workspace, and personalized RAG where two users ask the same question and should get different source material. In each case, a single retrieval path serves callers with different entitlements, which is exactly the condition that post-filtering handles poorly.
Index-per-tenant separation solves part of the problem. It is a sound way to keep customer A's data away from customer B, but it says nothing about which documents a particular employee inside tenant A may read, and internal leaks are often within-tenant.
Permission enforcement also does not fix permission modeling. Microsoft's Copilot security and governance guidance describes the oversharing problem directly: an assistant can honor the source system's access rules perfectly and still surface a file that was shared too widely in the first place. Correct enforcement over bad permissions still produces a leak, which is why the permission model deserves treatment as content modeling work, not a security bolt-on.
How does Sanity enforce permissions on content an agent retrieves?
Sanity enforces permissions at two distinct layers, and they answer different questions. At the content layer, access control runs on roles in the Content Lake. A content resource is a named subset of documents defined by a GROQ filter, attached to a custom role under Content permissions, so members holding that role can only act on documents matching that filter. The filter can depend on who is asking: the GROQ function `identity()` returns the project user ID of the user performing the current action, which makes `identity() in allowedEditors` a working document-level access rule. Roles can be assigned automatically from
At the agent layer, Sanity Context decides what an agent can read when it connects, not per query. A `groqFilter` configured on the Context MCP endpoint applies server-side, so nothing said in the conversation can widen what the agent reads, and a caller-supplied filter can only narrow it further. The design fails closed and fails early: every check runs on the agent's first request, a denied Knowledge Base refuses the connection with a 403 naming it, and a check that cannot be answered refuses with a 502 rather than falling open. This is the Power anything pillar of Sanity as the AI Content Operating System: give agents context with governance attached, rather than hoping a prompt holds the line.
Unlock New Possibilities with Sanity
With Access-controlled retrieval for RAG and agents under your belt, it's time to see what Sanity can do for you. Explore our features and tools to take your content to the next level.
Last updated: