PromptFu
01 Foundations1.7Foundation13 min

Blast radius and capability budgets

Least agency, and budgets as security limits rather than cost controls.

LLM03:2026LLM06:2026

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-classWhat it looks like in practice
Excessive functionalityA 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 permissionsA 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 autonomyHigh-impact actions taken without independent verification. A document-deletion tool that deletes without confirmation.
OWASP LLM03:2026 common examples of risk, condensed.

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.

Open-ended: unbounded scope
// 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)
Narrow: enumerable scope
// 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)
OWASP: define a strict schema for input parameters and validate contents prior to use. A narrow tool is also a tool you can reason about in a threat model.

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.

BudgetBoundsSourced?
max tool calls per taskRunaway loopsOWASP LLM06 #9 (step limits)
max recursion depthSelf-spawning agentsOWASP LLM06 #9
max wall-clock per runSlow-burn abuseOWASP LLM06 #9 (time limits)
per-run cost ceilingDenial of walletOWASP LLM06 #9
max records modifiedMass mutationOurs · extends LLM03 #9
max money movedFinancial lossOurs · extends LLM03 #9
max outbound messagesSpam, exfiltration volumeOurs
max external domains contactedExfiltration destinationsOurs
max memory writesPersistence attemptsOurs · see LLM01 #9
Be honest about provenance: the first four are OWASP's agentic circuit breakers verbatim. The rest are this course's extension of the same idea to business-impact units.

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.
OWASP LLM06:2026 · prevention #2, Hard Spending Caps

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

A hard ceiling that halts inference works while nobody is watching, cannot be talked out of triggering, and does not care why the spend happened. An alerting threshold is a detection control wearing a prevention costume: useful, and it stops nothing on its own.

Agentic circuit breakers

For agent loops, OWASP prescribes a bundle worth implementing together:

OWASP LLM06:2026 · prevention #9, Agentic Circuit Breakers
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

Self-check
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