Skip to main content
Back to blog
·6 min read

What Happens When an AI Agent Overspends? A Post-Mortem

A detailed walkthrough of how agent overspend happens — retry loops, stale intents, policy gaps — and the architectural defenses that stop it before it costs you money.

SecurityPost-MortemPolicy EngineOperations

It's Tuesday afternoon. Your procurement agent was supposed to buy one SaaS license for €49. Instead, it bought seven. Total damage: €343.

This isn't a hypothetical. Retry loops, timeout mishandling, and policy gaps are the three most common causes of agent overspend. They don't require a malicious agent — just a normal one operating in a system that wasn't designed for autonomous buyers.

Here's how each failure mode works, and how to prevent it.

Failure mode 1: The retry loop

The agent submits a payment. The checkout page takes 8 seconds to respond. The agent's browser tool times out at 5 seconds. The agent concludes the payment failed and tries again.

But the first payment went through. Now there are two charges.

The agent's logic is reasonable: "I didn't get confirmation, so it probably failed." This is exactly what a well-designed agent should think. The problem is the architecture, not the agent.

How Ovra prevents this:

  • One-time credentials. The DPAN and cryptogram issued for the first attempt can't be reused. The second attempt would use a new credential, which requires a new intent.
  • Intent deduplication. If the agent tries to create a second intent with the same purpose, amount, and merchant within a short window, Ovra detects it as a duplicate.
  • Verification before retry. The agent is instructed to call ovra_verify_transaction before retrying. If the first payment actually went through, verification catches it.

Failure mode 2: The stale authorization

The agent creates an intent on Monday for a €200 purchase. The purchase doesn't happen — maybe the checkout page was down, maybe the agent got interrupted. The intent stays open.

On Wednesday, the agent resumes its task. It finds the old intent and uses it. But the agent's daily limit has already been consumed by other purchases. The old intent bypasses the current-day policy check because it was approved on Monday.

How Ovra prevents this:

  • Grant expiration. Authorization grants expire after 30 minutes. Even if the intent is still "open," the grant is gone. The agent must request a new grant, which triggers a fresh policy evaluation.
  • Intent expiration. Intents themselves expire after 24 hours. Stale intents can't be reused days later.
  • Re-evaluation on credential issuance. When the agent requests credentials, Ovra re-checks the policy against current spend totals — not the totals from when the intent was created.

Failure mode 3: The policy gap

The agent's policy allows up to €500 per day. It makes five purchases of €99 each. Each individual purchase is well under the €200 per-transaction limit. But the total is €495 — dangerously close to the daily limit.

Then a sixth purchase comes in for €50. The daily total would be €545. If the policy check has a race condition — two intents evaluated simultaneously against the same daily total — both could be approved.

How Ovra prevents this:

  • Atomic spend tracking. Daily, weekly, and monthly spend totals are calculated from the database at evaluation time, not cached. Each policy check sees the most recent committed transactions.
  • SELECT FOR UPDATE. Database-level locking prevents two concurrent intent evaluations from seeing the same spend total. One waits for the other to commit.
  • Dual enforcement. Even if the application-level policy has a race condition, the card network enforces the hard limit. A card with a €500 daily limit will decline the sixth charge regardless of what the application thinks.

Failure mode 4: The scope creep

The agent is tasked with "set up the team's development environment." It interprets this broadly: GitHub Pro, JetBrains licenses, a staging server, a monitoring tool, a CI/CD service, and a domain name. Six purchases, none individually unreasonable, but collectively costing €847.

The agent didn't overspend on any single purchase. It overspent on the task.

How Ovra prevents this:

  • Monthly limits. A €1,000 monthly limit means the agent can't quietly accumulate thousands in charges across many small purchases.
  • Max usage count. Limiting the agent to N transactions total (or per period) puts a hard cap on purchase frequency.
  • Merchant allowlist. If the agent should only buy from GitHub and JetBrains, the policy can restrict it to exactly those merchants. Everything else is blocked.
  • Auto-approve threshold. Purchases above the auto-approve limit are held for human review. The agent can buy a €29 tool automatically, but a €200 license requires a human to click "approve."

Failure mode 5: The merchant mismatch

The agent creates an intent to buy from "Notion." The payment goes through, but the merchant descriptor on the charge is "Notion Labs, Inc." The verification system doesn't recognize the match and flags it as a mismatch.

This isn't overspend — it's a false positive. But false positives erode trust in the system. If operators start ignoring verification warnings, real mismatches will slip through.

How Ovra prevents this:

  • Fuzzy merchant matching. Verification uses substring matching, not exact string comparison. "Notion" matches "Notion Labs, Inc."
  • Amount tolerance. A configurable tolerance (e.g., 10%) allows for currency conversion differences, tax variations, and processing fees. An intent for €79 will match a charge of €79.20.
  • Lock to first merchant. For recurring purchases, the policy can lock the agent to the first merchant it transacts with. Subsequent purchases must match the same merchant descriptor.

The defense stack

No single mechanism prevents all overspend. The defense is layered:

| Layer | What it catches | |---|---| | Intent declaration | Agent must state purpose before spending | | Policy evaluation | Limits, restrictions, time windows | | Grant expiration | Stale authorizations can't be reused | | One-time credentials | Credentials can't be replayed | | Card network limits | Hard ceiling independent of application code | | Post-payment verification | Amount, merchant, and timing checks | | Audit trail | Every step is logged and attributable |

Each layer is independent. A failure in one doesn't compromise the others. The card network doesn't trust the policy engine. The verification system doesn't trust the agent's self-report. The audit trail records everything regardless of outcome.

The cost of not having this

Without these defenses, agent overspend is a when, not an if. The agent doesn't need to be buggy — it just needs to operate in a system that assumed a human would catch mistakes.

Humans catch mistakes by looking at their credit card statement at the end of the month. By then, the money is gone, the chargeback window is closing, and the agent has moved on to its next task.

Ovra catches mistakes before money moves. That's the difference between a policy engine and a credit card statement.