Least Privilege at the Data Layer: Relationship-Based Authorization for RAG
Part of the series The Authentication and Authorization Challenges of Agentic AI.
Everything covered so far in this series answers one shape of question: can this agent call this API. That’s necessary, but it’s a coarser question than the one that actually matters once an agent is retrieving documents to answer something in natural language. The question that matters is: can this agent retrieve this specific record, for this specific user, right now — and if the answer is no, does the system actually stop that record from reaching the model’s context, rather than just logging that it shouldn’t have? That’s the data-scoping gap, and it’s the one most commonly discovered after a leak rather than before one.
Why scopes and roles under-specify this problem
A scope like documents:read or a role like “employee” answers a category-level question well: this class of principal can generally read this class of resource. Neither answers the instance-level question a retrieval-augmented generation pipeline actually needs answered before assembling context for a model: out of the millions of documents behind that API, which specific ones is this requester, acting for this specific user, currently allowed to see?
Role-based access control was built for a world where permissions were relatively static and coarse-grained — a handful of roles, each mapped to a handful of resource categories. It breaks down exactly where RAG lives: permissions that vary per document, per folder, per project, per tenant in a multi-tenant system, changing constantly as documents are created, reshared, and reorganized. Trying to force that level of granularity into a role hierarchy usually produces either a role explosion (a new role for every meaningful combination of document access) or a retreat to overly broad roles that grant more than intended because modeling the precise boundary in RBAC terms became impractical.
The consequence for an agent is specific and serious: if the retrieval layer can’t answer the instance-level question, the model ends up with documents in its context window that the requesting user was never authorized to see. Nothing about that failure looks like a conventional security incident in the moment — there’s no failed authentication, no rejected API call, no error in a log. The wrong document just quietly becomes part of an answer. Prompt injection makes this worse, not by creating the underlying permission gap, but by giving an attacker a lever to actively steer a model toward retrieving or surfacing something it technically had access to but was never supposed to expose — a lever that only works if the retrieval layer failed to narrow the candidate set to begin with.
The pattern: relationship-based access control
Relationship-based access control (ReBAC), popularized by the model behind Google’s internal Zanzibar authorization system, answers a different, more precise question than RBAC does. Instead of storing “user X has role Y,” it stores facts as relationship tuples — object, relation, subject — such as “document 42, owned-by, user X” or “folder A, parent-of, document 42” or “user X, member-of, team B.” An authorization check then walks that relationship graph in real time: does a path exist connecting this specific user to this specific document, through some combination of ownership, group membership, or hierarchical containment, that satisfies the relation being asked about?
This is a strict superset of RBAC, not a replacement for it — a role is easily expressed as a relationship (“user X, has-role, editor, on, document 42”), so existing role-based thinking isn’t thrown away, it’s absorbed into a richer model that can also express relationships roles can’t: “the parent folder of this document,” “the current owner,” “a member of the team this project belongs to.” Many of the distinctions that would otherwise require attribute-based access control — attributes like department, seniority, or project membership — turn out to be expressible as relationships too, once you notice that “the user’s department” or “the document’s project” are themselves relational facts, not static properties baked into a token at authentication time.

Applying this specifically to retrieval
The part that matters for agentic RAG pipelines specifically: the relationship check needs to run before a document becomes part of what the model sees, not after, as a post-hoc validation of the model’s output. The retrieval step should filter its candidate document set down to only what the requester — the agent, acting for a specific user, in a specific session — is actually authorized to see, and only then hand that narrowed set to the model for it to reason over.
This matters because it changes what a successful attack actually looks like. If retrieval is properly scoped, a prompt injection attempt aimed at exfiltrating data can only ever surface something the requester already had legitimate access to — the attack surface shrinks to “can this leak facts within the user’s own authorized scope in an unintended way,” which is a meaningfully smaller and more contained problem than “can this leak anything in the entire document store.” Least privilege at the data layer doesn’t eliminate prompt injection risk, but it puts a hard boundary around its consequences.
Design guidance
Model the actual relationships, don’t force them into flat roles. If your access model regularly needs new roles just to express slightly different combinations of ownership, team membership, or folder hierarchy, that’s a signal the underlying access pattern is relational, not role-based, and modeling it as roles is producing either an explosion of nearly-identical roles or permissions broader than intended.
Enforce the check at retrieval time, as a filter, not as an audit step after the fact. The authorization decision needs to shape which documents enter the model’s context in the first place. A check that only validates after generation — “was the model allowed to say that” — is too late; the document has already influenced the output by the time that check runs.
Design for real-time evaluation at scale from the start. A retrieval pipeline serving agents may need to evaluate access decisions across a very large document set on every query, not occasionally in a batch job. This needs to be a system designed for that access pattern — a purpose-built relationship-authorization service, evaluated with the same performance expectations as any other request-path dependency — not a set of ad hoc joins bolted onto an application database as an afterthought.
Keep authorization logic out of application code, and log what actually happened. Decoupling the relationship model from the retrieval application itself means access policy can be audited, changed, and reasoned about independently of any single codebase — and, just as importantly, means you can log which specific documents were included or excluded from a given retrieval decision, rather than only logging that “the API call succeeded.” When someone eventually asks whether an agent should have been able to see a given document, that log is the difference between a fast, confident answer and a multi-day forensic reconstruction.
Treat this as complementary to everything else in the series, not a substitute for it. Scoping retrieval correctly doesn’t remove the need for a properly delegated, correctly identified agent principal calling the retrieval API in the first place — it answers a question one layer deeper than the ones the earlier posts in this series cover, and it depends on those earlier layers being solid to matter at all.
Next in the series: Governing Autonomous Systems: Auditability, Non-Repudiation, and Revocation, which closes the loop on everything covered so far — not preventing a bad outcome in the moment, but being able to prove, afterward, exactly what happened and why.