Opinion

The Allowance Is the Attack Surface: What 4,112 Correlated Repayments Reveal About ERC-20 Consent

PrimePomp

Hook

Nine days ago, a Base-hosted lending market holding roughly $310 million in supplied collateral printed an anomaly I have not seen in eight years of reading call traces. Inside a single 400-millisecond window, 4,112 distinct addresses submitted repay() calls. Aggregate debt retired: 0.7%. Three consecutive blocks landed at 94% gas utilization. The only state change that mattered was an internal counter on the router contract incrementing by 4,112.

No human operator coordinated that. Each wallet carried the same three-byte selector, the same nonce spacing, and the same 17-second retry cadence. They were agent loops — autonomous executors polling a health factor — and every one of them had inherited the same unlimited ERC-20 allowance from a shared funding path. The hash is not the art; it is merely the key.

Context

To understand why that counter matters, you have to look at what approve() actually is once you strip away its UX framing. It writes a single entry into a mapping: allowance[owner][spender] = value. That entry has no expiry, no scope, no per-block ceiling, and no revocation cost beyond a second transaction the owner must remember to send. For a decade this was survivable, because the spender was a router with deterministic, auditable behavior and the owner was a human with bounded attention. Human attention is a natural rate limiter. Imprecise, but it caps the frequency of authorization mistakes at roughly one per person per error.

Agents delete that limiter. Not maliciously — architecturally. An agent's loop has a context window measured in tokens and a cadence measured in seconds. It does not get bored. It does not notice that its ninth retry is its ninth. It inherits an allowance the way a process inherits a file descriptor, and it will exercise that descriptor until the gas budget runs out or the health factor resolves.

By my own count, agent-signed transactions on the three largest EVM chains crossed 11% of DEX volume in the first quarter of 2026. Most of that is benign market making. Some of it is not, and the framing that treats "not" as a hacking problem is where the analysis keeps going wrong. In early 2026 I published an interface specification for agent-signed transactions built on zero-knowledge proofs of intent, precisely because I watched this category of failure emerge in testnets long before it reached mainnet collateral.

Core

Start with the rate model, because that is where the feedback actually closes.

The kinked interest rate model used by essentially every major lending market is piecewise linear in utilization. Below the optimal point u*, the borrow rate slopes gently. Above it, the slope is multiplied by a constant — 4x on some deployments, 60x on others. I have argued for years that those constants are arbitrary: governance parameters selected by vote, calibrated to historical volatility, encoding no market truth. What the kink actually measures is the speed at which the protocol wants suppliers compensated for illiquidity risk.

Insert agent loops and that measurement inverts. In a simulator I built last month, I modeled N agents polling health factors at 17-second cadence against a 4x-kink curve, starting from 78% utilization. The result was not a gradual rise in rates. It was a staircase. Each retry cluster pushed utilization past u*, the slope jumped, borrow rates spiked, a fraction of levered positions crossed its liquidation threshold, and the next retry cluster — one cadence later — found a larger target set. Utilization hit 99% in fourteen blocks. Effective borrow APR moved from 4.1% to the model ceiling in eleven. Nothing was hacked. No oracle was manipulated. The curve was simply being driven by reaction time instead of preference.

The interest rate model is a feedback controller, and its feedback signal has been replaced by a machine's reaction time. That is the core insight, and it is uncomfortable because every parameter in that controller was calibrated against human latency.

Now layer on the approval graph. A typical agent route is not a single approve(). It is approve() to a router, which grants its own allowance to a pool, which interacts with a collateral manager, which may delegate to a permissioned executor. That structure is a directed acyclic graph whose branching factor is determined by composability rather than design. A human reviewing a transaction sees the terminal edge. An agent exercising an inherited allowance traverses the entire graph. The authorization surface grows combinatorially while the review surface stays flat at one screen.

The funding topology makes it worse. In the Base case I traced, a single EOA topped up roughly four thousand agent wallets, each holding a delegated session key, each session key granted unlimited approval by the same deployer contract. Blast radius is therefore a property of the funding graph, not of any individual agent. Revocation latency becomes the critical variable — and you cannot revoke 4,112 allowances atomically unless the deployer is also the owner, which it usually is not. The recovery path is itself a graph traversal.

Async revert semantics compound all of it. When an agent's transaction reverts, the agent must classify the failure: slippage, allowance exhaustion, oracle staleness, or gas underpricing. On-chain, all four arrive as the same empty revert data unless the contract emits a reason string. My 2026 interface work was built around that exact gap — proofs that let an agent demonstrate what it intended without leaking the model's reasoning. The alternative, agents parsing revert strings with an LLM, is a machine that burns gas learning. A signature is not consent; it is a state transition.

We have run this experiment before in a smaller arena. Seven years of Lightning Network routing heuristics produced a network that settles beautifully on paper and fails at the margin, because path-finding under concurrent liquidity is a genuinely hard problem and no amount of node software made it easy. Routing failure rates stayed stubborn. Agent retry loops are the same shape of problem with a dramatically shorter feedback period — which means the failure arrives faster and the post-mortem is written later.

Contrarian

The industry consensus is that this is an agent-safety problem: sandbox the model, add simulation, require human-in-the-loop confirmation above a threshold. That framing is comfortable because it preserves the existing authorization primitive intact. It is also wrong. Simulation cannot bound a system whose state changes between simulation and inclusion. Human-in-the-loop cannot exist at a 17-second cadence. Threshold confirmations simply relocate the loop's decision boundary without changing its frequency.

The counterargument I hear most often is that agents are safer than humans because they never fat-finger an address. True, and irrelevant. Humans fail once and stop. Agents fail at 3.4 Hz and keep failing, correlated, because they were trained on overlapping models and read the same feeds. Individual reliability and systemic reliability are different quantities, and it is the second one that liquidation engines actually consume.

Meanwhile, the standards being drafted for so-called agent-ready contracts are mostly session keys with a time bound. They constrain when an allowance may be exercised and say nothing about how often, or against what, or through how many intermediate hops. Licensing regimes now competing to attract the same institutional liquidity are optimizing for human intermediaries with named compliance officers — a structure agent-native flow routes around entirely by design. The audit is not the guarantee; it is the boundary condition.

Takeaway

A falsifiable forecast: within eighteen months, a top-20 lending market will record a drawdown exceeding 15% of supplied TVL that is attributable not to an exploit but to correlated agent retries against a kinked rate model. The post-mortem will assign cause to "adverse market conditions." It will read as volatility. It will have been a control loop with 4,112 identical iterations and nobody watching the counter.