Ask a team how their AI agent is authorised and the answer is usually some version of “it runs as the user”. It sounds conservative. The agent cannot do anything the person could not do, so what exactly is the exposure?
The exposure is that a person’s permission set was never designed to be exercised at machine speed by something with no sense of whether an action is unusual. Permissions that are safe for a human are safe partly because of the human, and inheriting them discards the part that was doing the work.
Why inheritance is the wrong default
Three properties bound what a person does with their access, and none of them survive being handed to an agent.
Attention. A person with export rights exports something when they need it, perhaps monthly. The right sits unused most of the time, and that dormancy is a real security property even though nothing enforces it.
Rate. A person with bulk-edit access can ruin perhaps a few dozen records before noticing. A loop can do the whole table between two heartbeats.
Accumulation. Role grants are additive and almost never pruned. After three years an operations manager holds permissions from two previous responsibilities plus a temporary grant from a migration nobody revoked. That set is survivable because of attention and rate. Remove those two and what remains is an access list nobody would have approved if written down as a single request.
There is a fourth problem, and it is the one that bites during an incident. If the agent acted as a person, your audit trail says that person did it. Accountability collapses into an identity that did not make the decision, and the question of who granted the agent its authority has no field to live in.
Inherited access against a dedicated agent identity
| Dimension | Agent inherits a user’s permissions | Agent holds its own scoped grant |
|---|---|---|
| Permission set size | Everything that user has accumulated | Exactly the tools this job needs |
| Who is accountable | Ambiguous: the log names a person who did not decide | The team that configured the agent |
| Effect of a role change | Agent’s power changes silently when HR updates a role | Unchanged until someone edits the agent |
| Prompt injection outcome | Reaches everything the user can reach | Reaches only the granted tools |
| Spend attribution | Mixed with that person’s activity | Attributed to the job |
| Revocation | Removing access breaks the person’s own work | Remove the tool, the person is unaffected |
The fourth row is the one to dwell on. Least privilege is not primarily an insider-threat control here. It is the containment layer for prompt injection in business AI, because an injected instruction can only cause damage the agent was already permitted to do.
The failure case: the reorder agent and the borrowed role
An operations manager configures an agent to plan stock reorders. The obvious implementation is to run it with her access, since she is the one who does this job manually.
Her role, accumulated over four years, includes stock and supplier data, which is what the job needs. It also includes customer contact records from a period spent covering account management, and a bulk-export capability granted during a migration eighteen months ago.
The agent is given the goal “identify slow-moving stock and the customers who previously bought it, so we can plan a clearance”. Entirely reasonable. It reads stock, reads the linked orders, and then, needing contact details to build its list, exercises the export capability it did not know it had, because it was never granted it; it was inherited. The customer table leaves the system into an attachment on an internal summary.
Nothing was hacked. No guardrail was bypassed. The agent used a permission it held, for a purpose consistent with its instructions, at a scale no one had considered because no one had ever looked at that role as a single object. The defect was committed at configuration time, in the single decision to inherit rather than to enumerate.
Scoping that actually works
Least privilege for agents is enumerated, per tool, with a data scope attached to each grant. Four rules cover most of it.
Grant capabilities, not roles. “Read invoices” is a capability. “Finance access” is a role, and a role is a bundle whose contents change when someone else edits it.
Attach a scope to every grant. Not “read invoices” but “read invoices belonging to the contact in this run”. An unscoped read tool is how a single-record task becomes a whole-table task, and scope should be enforced in the data layer rather than requested in the prompt. An agent asked to respect a boundary will sometimes respect it. An agent handed a query it cannot widen has no second option.
Separate read, draft and write. These are three different risk classes and should be three different decisions. Read and draft tools cannot alter your business regardless of what the agent concludes, which means you can be generous with them and strict with the small number that write.
Size the grant to the task, not to the operator. The right question is never “what can the person who set this up do”. It is “what is the minimum set that lets this specific job complete”, discovered by starting too small and watching runs fail.
That last point is worth defending, because it is the one people resist. Discovering a missing tool costs you a failed run and a two-minute edit. Discovering a surplus tool costs you an incident. The asymmetry is enormous and it points in one direction.
Blast radius, and the other two factors
Permissions are one of three multipliers. Blast radius is what an agent can affect before a human intervenes, and it is roughly the permission set, times the number of actions per run, times whether those actions execute without review.
That framing is useful because it shows which lever to pull first. Tightening autonomy alone leaves the permission factor intact, so a successful injection still reaches everything, it just queues rather than dispatches. Capping actions per run alone leaves a single catastrophic action available. Only the permission factor reduces the worst case, as opposed to the expected case, which is why it comes first and why the other two are tuned afterwards. The autonomy dimension is covered in suggest, approve, autonomous, and the run ceilings in the guardrails that run before an agent acts.
One class of permission deserves to be outside the model entirely. Some actions should not be grantable by ordinary configuration at all, but locked behind a separate switch that an autonomy setting cannot reach and a human approval cannot satisfy. Anything that moves money or stock belongs in that category, because the cost of a wrong grant there is not proportional to the care that went into making it.
How Oneop models agent permissions
An Oneop agent does not inherit anybody’s permissions. It is configured with a subset of a fixed catalogue of twenty tools, and a tool the model names that it was not granted is refused rather than improvised. Eleven of those twenty read or draft and cannot change anything at all; the nine that write all pass through one governed dispatch function, so there is no second path to a record.
Autonomy is stored on the agent rather than passed in when a run starts, which makes it a property of the job rather than of whoever pressed the button, and changing it is a deliberate edit. Every read an agent performs is scoped to the workspace the run belongs to, and that scoping happens in the data layer, not in the prompt. A build-breaking test fails the entire product if any model call on the agent surface is made without a workspace attached.
There are no per-agent credentials to store, because an Oneop agent never talks to an outside system. It reads Oneop’s own tables, and the single route outward is its email tool, which sends through whichever provider the workspace already uses. A capability that needs no secret is a stronger position than a secret that is well managed.
Money and stock actions sit outside the grant model on purpose. Posting a bill, issuing a purchase order, placing a credit hold or sending a payment reminder are refused at the single dispatch point until that whole class is switched on for the workspace, and the refusal holds in the most permissive autonomy mode and after a human approval, because the check sits below the approval rather than beside it. The tool split and the dispatch model are on the AI agents page, the identity and attribution model on the AI governance page, and the order to grant things in is set out in deploying AI agents safely.
Enumerate the tools. Scope every one. Let the first run fail for the right reason.