Giving an AI agent only the access it needs: a least-privilege checklist
Most agent mishaps come from too many tools, too many permissions or too much autonomy. A practical checklist for narrowing all three, based on OWASP guidance.

When an AI agent does something nobody wanted, the cause is rarely a clever attack. More often the agent was simply able to do more than its job required. A model misreads an instruction, or text from a web page nudges it off course, and the damage depends on what it had been handed.
The OWASP project lists this as LLM06:2025 Excessive Agency, one entry in its Top 10 for LLM applications. It describes a system that takes damaging actions in response to unexpected, ambiguous or manipulated model output, whatever caused the bad output. Hallucination and prompt injection are both named as possible triggers.
The useful part is the diagnosis. OWASP names three root causes, and each one is something you can tighten:
- Excessive functionality: the agent has tools it does not need.
- Excessive permissions: its tools can do more than the task requires.
- Excessive autonomy: it acts without anyone checking high-impact steps.
What follows is a checklist built on those three, with habits that work whatever framework you use. It is general good practice, not a substitute for a security review of your own system.
Start from the job, not the toolbox
Write down, in a sentence or two, what the agent is for. "Answers billing questions from the help centre" is a good one. Then list every tool and ask whether that sentence needs it. If you cannot connect a tool to the sentence, remove it.
A smaller tool list helps twice: it limits the damage of a mistake, and it makes the model's choices easier, because there are fewer wrong tools to pick.
Prefer narrow tools over open-ended ones
OWASP advises against open-ended capabilities such as running arbitrary shell commands, in favour of granular tools with a defined purpose. Compare these two:
run_command(cmd: string) # can do anything the account can do
get_invoice(invoice_id: string) # can do one thing, and you can validate the input
The second can be checked, logged, rate limited and explained to a reviewer. The first cannot. When an agent truly needs a shell, put it in a place where the worst outcome is contained. For example, our own piece on why every agent gets its own virtual machine explains one way to give agents a real computer that is not yours.
Trim what each tool may do
Even a well-named tool can be given too much. Think of each tool as an account:
| Question | Safer answer |
|---|---|
| Can it write, or only read? | Read-only unless writing is the point |
| Which data can it reach? | Only the records this task touches |
| Does it use a shared admin key? | No: a scoped credential per tool |
| Whose rights does it use? | The requesting person's, not a super-user's |
That last row is one of OWASP's recommendations: run extensions in the context of the specific user, with minimal scope. If a colleague cannot see a document, an agent acting for them should not either.
Let the downstream system say no
This is the point people skip. OWASP calls it complete mediation: enforce authorisation in the systems the agent calls, rather than trusting the model to decide what is allowed.
A model's judgement is not an access control. A prompt that says "never delete records" is a request. A database role that cannot delete records is a rule. Put the rule where the data lives. In a multi-tenant database, for example, row-level security means that even a confused or manipulated agent can only ever see one tenant's rows.
Important
Treat everything the model outputs as untrusted input to your tools. Validate arguments, check the caller's rights, and reject what does not fit, exactly as you would for a public API.
Put a person in front of the risky steps
Autonomy is a dial, not a switch. Sorting actions by their impact makes the setting easier to choose:
- Safe and reversible, such as reading, drafting, searching. Let the agent proceed.
- Visible but undoable, such as posting an internal note. Proceed and keep a log.
- Hard to undo or outward-facing, such as sending money, deleting data, emailing customers. Ask a person first.
OWASP recommends human-in-the-loop control for high-impact actions. The key is that the approval screen shows what will actually happen, with the real arguments, not a vague "the agent wants to continue".
If you are unsure whether you need an agent at all, or whether a fixed workflow would be enough, the post on choosing between a workflow and an agent is a good companion. Fixed steps have a smaller surface by design.
Keep a record, and a brake
OWASP is clear that logging, monitoring and rate limiting do not prevent excessive agency, but they limit the damage and help you notice. Cheap habits that pay off:
- Log each tool call with who asked, which agent, the arguments and the result, without writing secrets or tokens into the log.
- Set limits on calls per minute and on spend, so a loop stops by itself.
- Give yourself a single switch to pause an agent.
- Review the log when something looks odd, and tighten the tool that allowed it.
A ten-minute audit
Pick one agent you run today and answer these:
- What is its job in one sentence?
- Which tools does it have that the sentence does not need?
- For each tool, what is the most damaging call it could make with its current credentials?
- Which of those would a downstream system refuse, and which would it let through?
- Which steps would a person see before they happen?
The answers usually point to two or three easy fixes: drop a tool, swap a broad key for a narrow one, add an approval step. None of them make the agent less useful at its actual job. They make a bad day a smaller one.


