DEV Community

Cover image for Your AI Agent Has Too Much Power - Auditing Excessive Agency
Mohit Kumar
Mohit Kumar

Posted on • Originally published at mohitkumar1.hashnode.dev

Your AI Agent Has Too Much Power - Auditing Excessive Agency

Author: Mohit Kumar

Project: Bulwark – An open-source security stack for AI agents

GitHub: mk12002/Bulwark

This 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.

03_01

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.

03_02

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)│
└─────────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

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.

03_03

Defenses that actually work

  1. 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.

  2. 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.

  3. Gate high-impact actions. Shell, financial, destructive, and external-comms tools get a human confirmation. Non-negotiable.

  4. Bound autonomy. max_iterations, timeout_s, and a budget cap on every autonomous loop. A kill switch is not optional.

  5. Scan the parts too (--scan-parts runs 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 777 of 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


Top comments (0)