Author: Mohit Kumar
Project: Bulwark – An open-source security stack for AI agents
GitHub: mk12002/BulwarkThis article is part of the Bulwark series, where I explore practical approaches to securing AI systems, agentic workflows, and the AI software supply chain.*
Give an AI agent a tool that reads your files and a tool that sends email, and you have not created a productivity assistant — you have created a data-exfiltration pipeline that any prompt injection can trigger. Neither tool is malicious. The combination is. This class of risk is now OWASP LLM06: Excessive Agency, one of the top ten LLM risks — and there's almost no open tooling to actually measure it. So I built one.
TL;DR
Excessive Agency = an agent holds more capability, permissions, or autonomy than its task needs. It's OWASP LLM06 and a headline in the OWASP Top 10 for Agents (2026).
The dangerous cases are toxic combinations: a sensitive source (read files/secrets/DB) that can reach an egress sink (network/email) — an exfil path built from individually-fine tools.
Warden normalizes any agent config into one IR, builds a capability graph, finds source→sink paths, scores the assembly's agency 0–100, and — the money feature — rewrites the agent to least-privilege.
Named risk, near-zero open tooling. This is the whitespace: the closest prior art is a research paper, not a shipping tool.
Why this matters
Model scanners (like my other tool, Airlock) ask "is this part malicious?" But you can assemble a dangerous system entirely out of benign parts. The danger emerges from composition — the wiring, the scopes, the missing guardrails, the autonomy level.
OWASP put a name on it because it's the risk that turns every other AI vulnerability into an action. A prompt injection in a chatbot is embarrassing. The same injection in an agent with a shell tool and no human gate is a breach. The root causes are boring and universal: too many tools, over-broad scopes, long-lived secrets, missing approval gates, unbounded autonomy.
And yet — while there are mature scanners for models and emerging ones for MCP servers, there is essentially no widely-adopted open tool that ingests an agent config and tells you it's over-privileged. The best prior art is an academic paper. That gap is exactly why Warden exists.
The core concept: capabilities, not tool names
The trick to reasoning about an agent's power is to stop thinking about tool names and start thinking about capabilities. read_notes, fetch_url, run_bash, send_slack are names; underneath they are capabilities like FS_READ, NET_OUT, SHELL, SECRET_READ. Once every tool is tagged with its capabilities, over-privilege becomes a graph reachability problem.
The analogy: it's the confused-deputy problem, wearing an LLM costume. Each tool is a deputy with a legitimate power; the agent is a deputy that can be talked into chaining them. If a source of sensitive data can reach a sink that leaves the building, you have a leak waiting for a trigger.
How it actually works
One IR to rule every framework
Agents are configured a dozen ways — MCP client JSON, LangChain Python, a CrewAI agents.yaml, an OpenAI Assistants config. Warden normalizes all of them into a single AgentSpec IR, so the analysis engine never has to care which framework you used. Importers parse statically — the LangChain importer reads your .py with regex; it never executes your agent.
The ten things it looks for (A-codes)
| Code | Risk |
|---|---|
| A1 | Excessive tool scope (wildcard / root / unconstrained) |
| A2 ⭐ | Toxic combination — sensitive source reachable to an egress sink |
| A3 | Missing human-in-the-loop on high-impact actions |
| A4 | Over-broad system-prompt authority / weak guardrails |
| A5 | Unrestricted egress / exfiltration surface |
| A6 | Secrets embedded in the assembly |
| A7 | Excessive data / memory access |
| A8 | Unsandboxed code / shell execution |
| A9 | Untrusted / unscanned parts wired in |
| A10 | No runaway guards (iteration cap / budget / timeout) |
Plus a transparent agency score (0–100) in the header — a documented weighted sum over capability breadth, ungated high-impact tools, exfil paths, and missing limits. Not a black box; you can read the formula.
The money feature: it rewrites the agent
Finding problems is table stakes. Warden's --recommend hands you a hardened version:
$ warden audit devops-agent.yaml --recommend
HIGH A3 run_shell has no human-in-the-loop gate run_shell
HIGH A8 run_shell executes code/shell without a sandbox run_shell
MEDIUM A1 run_shell declares a wildcard scope run_shell
MEDIUM A10 autonomous agent has no runaway guards devops-agent
┌──────────────── Least-privilege recommendation ────────────────┐
│ Applied: │
│ - tool 'run_shell': add confirm gate (high-impact action) │
│ - tool 'run_shell': require sandbox for code/shell execution │
│ - tool 'run_shell': replace wildcard scope with an allow-list │
│ - agent: add runaway guards (max_iterations=25, timeout_s=300)│
└─────────────────────────────────────────────────────────────────┘
And policy profiles (--profile strict|balanced|permissive) set how strict the audit is without faking severities — permissive shows only blockers for a low-noise CI gate; strict shows everything for a full audit.
The attack surface — three scenarios
Scenario 1: the injection-to-exfil chain (A2 + A5). Attacker goal: steal data. Technique: a poisoned web page or document tells the agent, mid-task, to read a secret and POST it to attacker.com. Why it works: the agent has both SECRET_READ and NET_OUT, and nothing gates the egress. Detection: Warden's capability graph flags the source→sink path before deployment — you don't need the attack to happen to know the path exists.
Scenario 2: the unsandboxed shell (A8 + A3). Attacker goal: RCE on your infra. Technique: talk the agent into running a shell command. Why it works: the agent has a run_shell tool with no sandbox and no human confirmation. Detection: Warden flags A8 (unsandboxed exec) and A3 (no gate) on the same tool — a two-finding combo that screams "remove or gate this."
Scenario 3: the runaway loop (A10). Attacker goal: burn your budget or cause chaos. Technique: get the agent stuck in a self-reinforcing loop. Why it works: no max_iterations, no timeout, no budget cap. Detection: Warden flags any autonomous agent missing runaway guards.
Defenses that actually work
Audit before you ship, and apply the rewrite.
warden audit agent.yaml --recommend— then actually take the minimized spec. Every tool the agent doesn't provably need is attack surface.Break the source→sink pairs. If a role needs both a sensitive source and an egress sink, split it into two agents, or put an allow-list / mediation boundary between them.
Gate high-impact actions. Shell, financial, destructive, and external-comms tools get a human confirmation. Non-negotiable.
Bound autonomy.
max_iterations,timeout_s, and a budget cap on every autonomous loop. A kill switch is not optional.Scan the parts too (
--scan-partsruns Airlock on the MCP servers the agent wires in). A least-privilege agent built from poisoned tools is still compromised.
Hot take: "give the agent all the tools and let the model decide" is the
chmod 777of the AI era. It feels productive right up until a prompt injection turns your helpful assistant into a confused deputy with your credentials. Least privilege isn't a nice-to-have for agents; it's the only thing standing between a bad prompt and a breach.
Key takeaways
Reason in capabilities, not tool names — over-privilege is a graph-reachability problem.
Hunt toxic combinations (sensitive source → egress sink); they're built from benign parts.
Normalize to one IR so the analysis is framework-agnostic and never executes agent code.
Score it, then minimize it — a 0–100 agency score plus an automatic least-privilege rewrite turns audit into action.
Gate high-impact tools and bound autonomy — the two controls that stop injection-to-action.
Further reading
OWASP LLM06:2025 — Excessive Agency — the risk, defined by OWASP.
OWASP Top 10 for Agentic Applications (2026) — where agent-specific risks are codified.
Auditing MCP Servers for Over-Privileged Tool Capabilities (arXiv) — the closest academic prior art to Warden.
Intent-Governed Tool Authorization for AI Agents (arXiv) — a runtime complement to static least-privilege analysis.
Confused deputy problem — the 1988 idea that explains toxic tool combinations perfectly.



Top comments (0)