Securing Agents & Tools
- Apply least privilege — give an agent only the access its job needs
- Recognize the confused-deputy problem: an agent borrows your authority
- Layer the five defenses that shrink the blast radius when an agent is tricked
- Decide which actions demand a human in the loop
- Validate tool inputs so a bad or manipulated argument can't execute
The moment an AI can take actions (call tools, run code, hit APIs), it inherits a security model. The goal isn't to make the model un-trickable — it's to make sure that even if it's tricked, it can't do much harm.
The core principle: least privilege
Give an agent the minimum access its job requires, nothing more.
- A doc-summarizer needs read, not write or network.
- A reviewer needs to read code and post a comment — not push or deploy.
- Scope tools, API keys, and file access per-task. A narrowly-scoped agent that gets injected can only do narrow damage.
The confused-deputy problem
An agent often acts with your authority (your tokens, your sessions). If attacker-controlled input steers it, the attacker borrows your privileges — a "confused deputy." Defense: don't hand the agent ambient authority it doesn't need, and require explicit, scoped credentials for sensitive tools. When the agent reaches tools through a remote MCP server, this same trap has a specific rule — see securing MCP servers.
Defense layers
Stack these — no single one is sufficient. Each layer assumes the ones above it might fail.
- Run code and file operations in containers or ephemeral dirs with no access to the broader system or secrets. If the agent is tricked, it plays in a box.
- Decide which commands, which domains, and which paths are permitted — deny the rest. In Claude Code, that's permissions (/docs/claude-code/permissions).
- Require explicit approval for irreversible or sensitive actions: send money, send email, delete, deploy, or change production config.
- Don't let one agent simultaneously hold secrets, read untrusted content, and make arbitrary outbound calls — that combination is the exfiltration path.
- Record what tools the agent actually invoked and with what arguments, so you can audit behavior and catch drift.
Put an allowlist in writing
"Allowlist the dangerous surface" is easy to nod at and easy to skip. In Claude Code it's concrete: a settings.json that permits the narrow set of commands and domains the task needs and denies the rest. Start restrictive and widen only when a real task blocks.
A least-privilege Claude Code permissions block
{
"permissions": {
"allow": [
"Read",
"Edit",
"Bash(npm test:*)",
"Bash(npm run build:*)",
"Bash(git status)",
"Bash(git diff:*)"
],
"deny": [
"Bash(git push:*)",
"Bash(rm:*)",
"Bash(curl:*)",
"Read(./.env)",
"Read(./secrets/**)"
]
}
}The deny list wins over allow, so blocking .env and secrets/** holds even if a broad Read is granted. See permissions for the full rule syntax and precedence.
Tools have schemas — validate them
Tool inputs the model produces can be wrong or manipulated. Validate arguments before executing, and return errors as results so the agent recovers instead of retrying blindly.
Check yourself
0/3- Least privilege first: scope tools, keys, and file access per task so a tricked agent can only do narrow damage
- An agent acts with your authority — don't hand it ambient privileges it doesn't need (the confused-deputy problem)
- Stack the five layers: sandbox, allowlist, human-in-the-loop, separate trust zones, log and review
- In Claude Code, deny rules beat allow rules — block .env and secrets paths explicitly
- Validate tool arguments before executing, and return errors as results so the agent recovers instead of retrying blindly