Role-based access control for AI assistants and agents
An AI agent should act with the permissions of the person it serves, capped by its own role, and every check belongs in retrieval and tools, not in the prompt.
Role-based access control for an AI assistant means the assistant never sees or does more than the person using it is allowed to, and the agent itself has a role that limits what it can do even for a powerful user. Its effective permissions are the overlap of the user's role and the agent's role. That check has to be enforced by the data stores and tools the agent calls, because a model cannot be trusted to refuse on its own.
Most teams get the first version of this wrong in the same way. They build an internal assistant, connect it to the HR system, the CRM and a document store with one service account that can read everything, and then write "only answer questions the user is entitled to" in the system prompt. It works in the demo. It fails the first time someone asks a slightly clever question.
Here is an illustration. A sales manager types: "Summarise the comp review notes for my region so I can plan hiring." The assistant searches the document store, and because its service account can read the HR folder, the top results include a spreadsheet of salary bands and a performance note about a named employee. The system prompt says not to share HR data with sales staff. The model decides this is a planning question, not an HR question, and helpfully summarises. Nothing was hacked. The access model simply lived in the wrong place.
RBAC in one paragraph
RBAC is old and well understood, which is good news. NIST credits David Ferraiolo and Rick Kuhn with formalising it in 1992, and the model became an American national standard, ANSI/INCITS 359, in February 2004, revised in 2012. The idea is that each user gets one or more roles and each role carries a set of permissions, so access is managed at a level that matches how the organisation is actually structured. You do not grant one analyst read access to thousands of folders one by one; you make her a member of "finance-analyst" and the role decides.
None of that changes for AI. What changes is that a new actor now sits between the person and the systems, and it can be talked into things.
Three identities, not one
Every agent action involves at least three identities, and the design question is how they combine.
There is the user, the human who asked. There is the agent, a piece of software with its own configuration, tools and purpose. And there is the credential the tool call finally presents to the downstream system, which might belong to the user, to the agent, or to a shared account nobody remembers creating.
The OAuth Token Exchange standard, RFC 8693, gives useful words for this. It distinguishes impersonation, where the actor "is given all the rights that B has", from delegation, where the actor "still has its own identity separate from B". It also defines an act claim that records in a token that delegation happened and which party is acting, with nested claims forming a chain when one service calls another.
Delegation is the model I would choose for agents. With impersonation, the CRM sees a request from the sales manager and has no idea a model wrote it. With delegation, it sees "agent crm-assistant, acting for this sales manager", which means it can apply rules to both, and your logs can tell the difference between a person exporting 10,000 contacts and an agent doing it on their behalf.
Shared service accounts are the worst of the three options. They turn the agent into a way around your existing access model: any user who can talk to the agent can reach anything the account can reach.
The rule: user role, agent role, and the overlap
The simplest correct policy is an intersection. The agent may do something only if the user is allowed to do it and the agent's own role allows it.
The user's role stops the leak in the illustration above. The sales manager cannot open the HR folder in the HR system, so the agent acting for them cannot either.
The agent's role stops a different failure. Suppose the CFO uses a meeting-notes assistant. The CFO can approve payments, but there is no reason a notes assistant should ever be able to. If the agent's role is "read calendar, read and write notes", then even a perfectly crafted prompt injection in a meeting invite cannot make it move money, because the payment tool is not in its role at all. OWASP's entry on excessive agency names the three root causes of this kind of damage as excessive functionality, excessive permissions and excessive autonomy, and the agent role is how you cut the first two.
The intersection is easy to describe and annoying to build when data, pipelines and agents each keep their own permission lists, because then "the user's role" means three different things. CloudOEngine puts data connections, pipelines and the AI runtime under one permission model and one audit trail, so the role that decides what a person can query is the same role that decides what an agent acting for them can query.
Where the check has to happen
OWASP's mitigation list for excessive agency contains the sentence I would pin above every AI team's desk: "Implement authorization in downstream systems rather than relying on an LLM to decide if an action is allowed or not." The same entry says actions taken for a user should run on downstream systems "in the context of that specific user", with the smallest scope that does the job.
In practice that gives you three enforcement points.
The first is retrieval. If the agent searches documents, the search itself must only return what the user may read. The second is the tool layer: every tool the agent can call checks the caller's identity and scope before doing anything, exactly as it would for a request from a web form. The third is the downstream system's own permissions, which you should keep, not bypass. If your ERP already knows that a sales manager cannot see payroll, pass the user's identity through and let the ERP say no.
The prompt is not an enforcement point. It is fine to tell the model about the user's role so it can phrase a polite refusal or avoid wasting a tool call, but treat that as user experience. Our article on prompt injection explains why: any text the model reads can override its instructions, so instructions cannot be the thing standing between a user and data they should not see.
Retrieval is an access decision
RAG systems leak in a quiet way. Documents are chunked, embedded and stored in one index, the permissions that lived on the original files are dropped along the way, and the search returns the most similar chunks regardless of who is asking.
OWASP's 2025 entry on vector and embedding weaknesses describes exactly this: "Inadequate or misaligned access controls can lead to unauthorized access to embeddings containing sensitive information." It calls out shared indexes "in multi-tenant environments where multiple classes of users or applications share the same vector database", and recommends permission-aware vector stores with strict logical and access partitioning.
The fix is mechanical once you accept it is needed. When you ingest a document, copy its access labels (groups, department, tenant, sensitivity) onto every chunk as metadata. At query time, resolve the user's groups and apply them as a filter inside the search, so restricted chunks are never candidates at all. Filtering after ranking is weaker: the restricted chunk was still retrieved, and if the filter step has a bug, it goes straight into the model's context. Our vector database explainer covers why filtered search can also return fewer results than you asked for, which is worth testing with your real permission filters.
Two details get missed. Permissions change, so a person who moves from HR to sales should lose HR results the same day, which means the labels on chunks have to be refreshed when the source permissions change as well as when the document text does. And between tenants, a metadata filter is the wrong tool; separate tenants should be separated at the storage and key level so a missing filter cannot cross them.
Four ways to wire identity, compared
| Pattern | What the downstream system sees | Main risk | When it is acceptable |
|---|---|---|---|
| Shared service account | One account for every user | Any user reaches everything the account can | Background jobs with no user data, with a narrow role |
| Impersonation | The user only | No record that an agent acted; agent gets all of the user's rights | Rarely; read-only lookups with short-lived tokens |
| Delegation | The user and the agent | More setup: token exchange, two identities to log | Default for interactive assistants |
| Delegation plus approval | User, agent and an approving person | Approval fatigue if every action needs it | Payments, deletions, external messages, bulk changes |
Tokens, tools and the confused deputy
If your agent reaches tools through the Model Context Protocol, the protocol's authorization rules already encode several of these ideas. The 2025-06-18 specification says MCP servers "MUST validate that access tokens were issued specifically for them as the intended audience", and that a server calling an upstream API must use a separate token for that API: it "MUST NOT pass through the token it received from the MCP client." Clients must name the target server with the resource parameter from RFC 8707, which binds each token to one audience.
The reason is the confused deputy problem. A server that accepts a token meant for something else, or forwards a user's token downstream, lets the downstream system believe a request was checked when it was not. The same rule applies to tools you write yourself: each tool should receive a token scoped to it, with only the permissions that tool needs, and should reject anything else. Our MCP explainer covers how the protocol fits together.
When roles stop being enough
Roles answer "can this kind of person do this kind of thing". They are bad at conditions. A procurement agent might be allowed to raise purchase orders, but only below a certain value, only for approved suppliers, and only during a financial period that is still open. Encoding that as roles produces a role explosion.
That is where attribute-based rules help. NIST SP 800-162 defines ABAC as a method where access is decided "by evaluating attributes associated with the subject, object, requested operations, and, in some cases, environment conditions" against policy. For agents, useful attributes include the data's sensitivity label, the record's region, the amount or row count of an action, the time, and whether the run was started by a person or by a trigger.
I would keep RBAC as the backbone and add a handful of attribute rules on top, rather than starting with a full policy engine. And for the actions where a wrong call costs real money or reputation, the best rule is a person. OWASP lists human approval of high-impact actions as a mitigation for excessive agency. CloudOEngine's Autopilot runs triggered agents with approval rules, so a person approves the action, in the app or through an email approve link, before it runs. Our piece on human-in-the-loop agents covers which actions deserve that step.
Log both identities, and the denials
An access model you cannot inspect is one you cannot defend in an audit. Every agent action should record who asked, which agent acted, which policy decision was made, which tool was called with which arguments, and what came back. Log denials too. A sudden run of denied requests from one assistant is often the first sign that a prompt injection is probing for reach, or that a role was set up wrong and people are working around it.
This is also where delegation pays off, because the log can say "agent crm-assistant, for user 4471, denied export of 12,000 rows: exceeds agent limit" instead of a bare service account name (an illustrative log line). In CloudOEngine every agent step and tool call is traced and inspectable, so a reviewer can open a run and see what the agent tried, what it was allowed to do and what it actually did.
Where I would start
If you already have an assistant in production on a shared account, this order fixes the biggest exposure first.
- List every tool and data source the agent can reach and the credential it uses for each. Mark the shared accounts.
- Give the agent its own role with only the tools its job needs, and remove the rest. It is usually a small configuration change, and it immediately cuts what a fooled agent can do.
- Pass the user's identity to retrieval and add permission labels to every chunk. Test with a low-privilege account and a question you know touches restricted documents.
- Move tool calls from shared credentials to per-user, per-tool scoped tokens, starting with tools that write.
- Add approval for the short list of actions that move money, delete data or send messages outside the company.
- Turn on logging of both identities and of denials, and review a week of it with the system owner.
How CloudOEngine helps
CloudOEngine is one platform and one console for connecting data (databases, files and camera streams), running pipelines, and running AI through an AI runtime with an LLM gateway, agents with tool access and RAG, alongside Vision AI and live video. All of it shares one permission model and one audit trail. For access control that means the role deciding what a person can query is the same role applied to an agent acting for them, rather than a separate list maintained per tool.
Governance is included, not upsold: tenant isolation, role-based access, audit logs and per-tenant encrypted secrets. Tenant isolation keeps one tenant's data apart from another's, and role-based access is the basis for the user-and-agent intersection this article describes.
Agents run real tools, for example filing a ticket, and every step and tool call is traced and inspectable. When someone asks why an assistant answered the way it did, or tried an action it should not have, you can open the run and see each tool call and its arguments.
Autopilot runs triggered agents with approval rules. A person approves an action, in the app or through an email approve link, before it runs, which gives you a human check on exactly the high-impact actions where roles alone are too blunt.
CloudOEngine is built in Bengaluru, India.
Book a demo or see the AI runtime.
Frequently asked questions
How does role-based access control apply to AI agents?
The agent should never see or do more than the person it is working for is allowed to, and it should have its own role that caps what it can do even for a powerful user. Its effective permissions are the overlap of the two, checked by the systems it calls rather than by the model.
Can I enforce access control by telling the model in the system prompt?
No. A system prompt instruction such as 'do not show salary data to sales staff' is a request, not a control, and prompt injection or a plain mistake can get past it. OWASP's guidance on excessive agency says to implement authorization in downstream systems rather than relying on an LLM to decide if an action is allowed.
Should an AI agent use a shared service account?
Avoid it for anything that touches user data. A shared account with broad rights lets any user reach whatever the account can reach, simply by asking the agent. Pass the user's identity through to each tool and data source, and keep service accounts for narrow background jobs with their own limited role.
What is the difference between delegation and impersonation for agents?
RFC 8693 describes impersonation as the actor being given all the rights of the subject, while with delegation the actor keeps its own separate identity. Delegation is the better model for agents because logs and downstream systems can see both who asked and which agent acted.
How do I stop a RAG assistant from leaking documents a user cannot open?
Store each chunk's access labels next to its embedding and filter on the user's groups inside the search, before results are ranked and passed to the model. OWASP's 2025 guidance on vector and embedding weaknesses recommends permission-aware vector stores and strict partitioning of datasets.
Is RBAC enough, or do I need attribute-based access control?
Roles cover most of the who-can-do-what decisions. Add attribute rules, which NIST SP 800-162 describes as evaluating attributes of the subject, object, operation and environment, for conditions such as region, amount thresholds or data sensitivity, and require human approval for high-impact actions.
Sources
- Role Based Access Control project (NIST CSRC)
- LLM06:2025 Excessive Agency (OWASP Top 10 for LLM Applications)
- LLM08:2025 Vector and Embedding Weaknesses (OWASP Top 10 for LLM Applications)
- RFC 8693: OAuth 2.0 Token Exchange (IETF, January 2020)
- Model Context Protocol specification 2025-06-18: Authorization
- NIST SP 800-162: Guide to Attribute Based Access Control (ABAC) Definition and Considerations
