Walk into any office building and you get a badge. It opens the lobby. Maybe your floor. It doesn’t open the server room, the CFO’s office or the loading dock at 2am. If you need more, someone approves it, and the door logs every swipe.
We spent a decade getting this right for people in software too. Single sign-on. Least privilege. Approvals for production. Audit logs for everything.
Then agents showed up, and a lot of teams handed them a long-lived token with admin rights and called it a pilot.
The same four controls
Everyone already agrees on four things for human access:
- Identity. You know who did it.
- Least privilege. They can only do what their job needs.
- Approvals. Big changes need a second person.
- Audit. You can see what happened, after the fact.
Agents need the same four. Too often they get one, if that.
OWASP already named the problem
OWASP’s Top 10 for LLM Applications has an entry for this: LLM06:2025 Excessive Agency . It describes the vulnerability that “enables damaging actions to be performed in response to unexpected, ambiguous or manipulated outputs from an LLM, regardless of what is causing the LLM to malfunction.”
That last part matters. It doesn’t matter whether the model hallucinated, got a bad prompt or got prompt-injected by something it read. If the agent can do damage, eventually it will.
OWASP says the root cause is “typically one or more of: excessive functionality; excessive permissions; excessive autonomy.” Here’s what each one looks like in a dev workflow.
Excessive functionality. You give an agent a tool to read files in a repo. The tool you picked can also delete them. OWASP’s version of this example is a document reader that can also modify and delete documents.
Excessive permissions. The agent’s tool connects to a database or a cloud account with a shared admin identity, because that was the credential lying around. OWASP’s example is an extension meant to read data that connects with an identity that also has UPDATE, INSERT and DELETE.
Excessive autonomy. The agent can merge to main, delete a branch or post to a customer channel without anyone looking. OWASP’s example is an extension that deletes a user’s documents “without any confirmation from the user.”
Identity: who is this, and who sent it?
Every agent run should answer two questions: which workload is this, and which human started it?
The workload part means the agent runs as its own identity, not as yours and not as a shared service account. I wrote about one way to do that in workload identity federation for agents . Short-lived credentials tied to the workload beat a token in an environment variable every time.
The human part is just as important. OWASP’s guidance is to “Track user authorization and security scope to ensure actions taken on behalf of a user are executed on downstream systems in the context of that specific user.” If I ask an agent to fix a bug, it should be able to touch what I can touch, and no more.
Permissions: scope by task
The easiest rule I know: a rollback agent doesn’t need to write to the billing repo.
OWASP’s mitigation list reads like a least privilege checklist:
- Limit the tools an agent can call to the minimum necessary.
- Limit the functions inside each tool. A mail summarizer only needs to read mail.
- Avoid open-ended tools like “run a shell command” or “fetch a URL” when a narrow tool will do.
- Limit the permissions each tool has on downstream systems.
And the one I’d underline: enforce it in the downstream system. OWASP calls this complete mediation, implementing “authorization in downstream systems rather than relying on an LLM to decide if an action is allowed or not.” The database should refuse the delete. The prompt shouldn’t be the only thing standing in the way.
Here’s what a badge list for a small team’s agents might look like:
| Agent | Can read | Can write | Badge |
|---|---|---|---|
| Triage | Logs, metrics, tickets | Ticket comments | 0012 |
| Rollback | Deploy history | Rollback pipeline only | 0017 |
| Fix | Service repo | Branches and PRs, not main | 0023 |
| Fan-out | Every repo in scope | Branches and PRs, not main | 0031 |
| Rubber duck | Nothing | Nothing | 0042, lobby only |
Autonomy: decide before it runs
Write down three lists before an agent does real work:
- Do alone. Low risk and easy to undo. Comment on a ticket. Open a PR. Roll back through the normal pipeline.
- Propose, a person approves. Merge to main. Change config in production. Anything that talks to a customer.
- Never. Delete data. Change its own permissions. Touch billing.
OWASP says the same thing in one line: “Utilise human-in-the-loop control to require a human to approve high-impact actions before they are taken.” That’s the same rule I used in the pager post : if you wouldn’t let a new hire do it alone on their first night of on-call, the agent shouldn’t do it alone either.
Audit: if you can’t replay it, you can’t fix it
The last control is the one people notice only after something goes wrong.
For every agent run you want to know what it was asked, what it read, which tools it called with which arguments, what came back and what it changed. OWASP lists logging and monitoring the activity of extensions and downstream systems as a way to limit damage, along with rate limiting so a bad loop can’t do a thousand bad things before someone notices.
If an agent run does go sideways, stop it without losing the record . A postmortem on an agent is only as good as the trail it left.
Governance is how you get to yes
None of this is about slowing agents down. It’s the opposite.
The fastest way to get an agent approved is to answer a security reviewer in one sentence: “It runs as its own identity, it can only touch these three things, anything bigger needs a person, and here’s the log.” “It uses my token” gets you a meeting.
Badges never stopped anyone from doing their job. They’re why you can let a new person in the building on day one.
Give the agent a badge. Just make sure it’s the right one.