Blast radius and capability budgets
Least agency, and budgets as security limits rather than cost controls.
The last foundations module turns everything before it into numbers. If the model will occasionally be compromised, the remaining question is arithmetic: how much damage can one compromised session do before something stops it? That number is a design choice, and most teams have never made it.
Least agency
Least privilege, extended to autonomy. OWASP's Excessive Agency entry breaks the problem into three sub-classes. Check the system against each separately, because they fail for different reasons.
| Sub-class | What it looks like in practice |
|---|---|
| Excessive functionality | A tool chosen for read access that also modifies and deletes. A tool trialled in development and never removed. A "run one specific shell command" tool that fails to prevent other commands. |
| Excessive permissions | A read tool whose database identity also holds UPDATE, INSERT and DELETE. A per-user tool connecting with a generic high-privilege account that can see every user's files. |
| Excessive autonomy | High-impact actions taken without independent verification. A document-deletion tool that deletes without confirmation. |
The controls follow the same shape, in rough value order: minimize tools (if the system does not need URL fetching, do not offer a URL-fetching tool), minimize tool functionality (a mailbox summariser needs read, not send or delete), avoid open-ended tools, minimize tool permissions at the downstream identity, and execute in the user's context.
The open-ended tool problem
Avoiding open-ended tools has the best ratio of effort to risk removed. An agent should not hold a generic magical function when it needs three specific ones.
// One tool, unlimited semantics. Every shell command
// ever written is now in scope, and no schema constrains it.
execute(command: string)
// Same problem, different clothes:
fetchUrl(url: string)
runQuery(sql: string)// Three tools, enumerable semantics. Each takes an ID,
// validated against a strict schema before use.
getExpense(expenseId: string)
attachReceipt(expenseId: string, receiptId: string)
submitExpense(expenseId: string)Capability budgets
Even a perfectly scoped agent can do serious damage by doing a permitted thing many times. A mail agent authorized to send email is fine. The same agent sending a million emails is an incident.
The reframe that makes this land. Ours, assembled from OWASP's LLM03 and LLM06 controls rather than quoted:
Capability budgets are blast-radius controls that happen to cap spend.
A compromised mail agent able to send one message is fundamentally safer than one able to send a million, and the difference between those two systems is a configuration value.
| Budget | Bounds | Sourced? |
|---|---|---|
max tool calls per task | Runaway loops | OWASP LLM06 #9 (step limits) |
max recursion depth | Self-spawning agents | OWASP LLM06 #9 |
max wall-clock per run | Slow-burn abuse | OWASP LLM06 #9 (time limits) |
per-run cost ceiling | Denial of wallet | OWASP LLM06 #9 |
max records modified | Mass mutation | Ours · extends LLM03 #9 |
max money moved | Financial loss | Ours · extends LLM03 #9 |
max outbound messages | Spam, exfiltration volume | Ours |
max external domains contacted | Exfiltration destinations | Ours |
max memory writes | Persistence attempts | Ours · see LLM01 #9 |
The business-impact rows matter most, and OWASP points that way itself. Its rate-limiting guidance notes that simple thresholds can be based on invocation counts, while context-aware thresholds could be based on the cumulative value of an input parameter to a tool, which is a “max money moved” budget described generically.
Hard ceilings, not alerts
One line in OWASP's Unbounded Consumption guidance is sharper than most security advice gets:
Set non-overridable budget ceilings per API key, user, team, and cloud account. These must be enforcement mechanisms that halt inference when exceeded, rather than alerting thresholds that fast-accumulating workloads can outpace.
Read it as an indictment of the default setup. Almost everyone has alerts. Alerts assume a human is watching and can act faster than the workload accumulates, which fails at 3am and fails by design against an attacker who chose the timing. OWASP adds that ceilings should account for cost differences between modalities and tool protocols, because a multimodal upload and a text turn are not the same unit of spend.
Bounds blast radius· survives adaptive attack
Agentic circuit breakers
For agent loops, OWASP prescribes a bundle worth implementing together:
Enforce on all agent executions:
· step limits
· recursion depth limits
· time limits
· per-run cost ceilings
Use state hashing to detect recursive loops.State hashing is the clever one, and it is rarely implemented. A step limit catches a loop eventually. Hashing the agent's state catches an exact repeat on the second iteration, because revisiting the same state produces the same hash. Cheap, and it turns “this agent burned its whole budget” into “this agent stopped after two redundant steps.”
Know what it misses. It only fires on states that are byte-identical after canonicalisation, so a timestamp, a retry counter, a nonce or a request ID anywhere in the hashed state defeats it, and so does a loop that drifts slightly each time round. Hash a deliberately narrow projection of the state rather than all of it, and keep the step, time and cost ceilings underneath. Those catch the cases hashing cannot.
Deep diveBudgets as a red-team target, not just a control3 min›
Once budgets exist they become something to attack. Three questions for the test plan.
Is the ceiling actually non-overridable? A budget stored where the agent can read or write it is not a budget. A budget passed as a tool argument is worse.
What is the unit? A limit of ten tool calls means nothing if one call can modify ten thousand records. Budgets keyed to invocation counts are the ones attackers ignore. Budgets keyed to cumulative business impact are the ones that bite.
What happens at the boundary? Fail-closed or fail-open? An agent that hits its ceiling and proceeds unbudgeted has a limit that functions as a log line. Test the boundary specifically. Module 6.5 covers designing these tests, and module 4.7 has the fuller economic-attack question set.
Check yourself
1. The agent has a 20-tool-call limit per task. One of its tools is
bulkUpdate(filter, changes). Is the limit meaningful?
2. Why does OWASP insist ceilings must halt inference rather than
alert? Give the failure mode.
3. What does state hashing catch that a step limit does not?
4. Rank by risk removed per hour of work: (a) minimize tool
permissions, (b) tune the system prompt, (c) replace an
open-ended tool with three narrow ones.Sources
- T1OWASP Top 10 for LLM Applications 2026 · LLM03:2026 Excessive Agency (three sub-classes; mitigations 1–5; #9 rate limiting and the cumulative-parameter threshold)
- T1OWASP Top 10 for LLM Applications 2026 · LLM06:2026 Unbounded Consumption (#2 Hard Spending Caps; #9 Agentic Circuit Breakers including state hashing; #1 token-rate and pre-flight estimation)
- ·The business-impact budget rows (money moved, records modified, outbound messages, external domains, memory writes) are this course's extension of OWASP's controls, marked as such in the table above