← Back to Blog

The Anatomy of a Wallet Drain: How One Logic Loop Cost $100k

The most dangerous bug in Agentic Finance isn’t a hacker stealing a private key. It’s the agent doing exactly what it was programmed to do—too many times.

Let’s dissect a hypothetical (but all too common) “Infinite Loop” drain event.

The Setup

A DeFi trading agent is built to monitor the price of ETH and buy dips automatically.

Configuration:

  • Trigger: If ETH drops below $3,000, buy 1 ETH
  • Balance: $100,000 USDC
  • Wallet: Standard EOA (Externally Owned Account) with the key stored in .env
  • Deployment: Running on AWS EC2, 24/7

The developer is proud of their creation. It’s going to make money while they sleep.

The Bug

The developer writes a monitoring loop:

while (true) {
  const price = await getPrice("ETH");
  if (price < 3000) {
    await wallet.buy("ETH", 1);
    console.log("Bought the dip!");
  }
  // Missing: sleep() or state update
}

Two problems:

  1. No sleep() between iterations—the loop runs as fast as the CPU allows
  2. No state tracking—the agent doesn’t know it already bought

The developer tested with small amounts. It worked. They deployed to production with $100k.

The Drain: Second by Second

00:00:01 — ETH drops to $2,999. Trigger condition met.

00:00:02 — Agent submits transaction #1: Buy 1 ETH ($3,000).

00:00:02.1 — Loop completes. Price still $2,999 (blockchain hasn’t confirmed yet). Trigger still met.

00:00:02.2 — Agent submits transaction #2: Buy 1 ETH ($3,000).

00:00:02.3 — Transaction #3.

00:00:02.4 — Transaction #4.

00:00:05 — 30 transactions submitted. $90,000 committed.

00:00:10 — Wallet balance: $0.00 USDC. 33 ETH purchased (with slippage). Gas fees: ~$500.

Total time from trigger to drain: 10 seconds.

The developer wakes up to a Telegram alert: “Balance low.” They check the wallet. Empty.

The Hidden Costs

The $100,000 loss is just the beginning:

Slippage: Buying 33 ETH in 10 seconds moves the market. Average purchase price: $3,150 instead of $2,999. Additional loss: ~$5,000.

Gas fees: 33 transactions × ~$15 each = ~$500.

Opportunity cost: The ETH position is now 10x larger than intended. When ETH drops further, losses compound.

Reputation: If this is a fund or DAO, the incident destroys trust.

Why This Happens More Than You Think

This isn’t a contrived example. Similar incidents happen regularly:

GetOnStack (2024): A multi-agent system entered a recursive conversation loop for 11 days, racking up $47,000 in API costs before anyone noticed.

DeFi Bots (ongoing): MEV bots regularly drain themselves through misconfigured loops and failed arbitrage attempts.

Customer Support Agents: Bots that auto-refund without limits have processed thousands in fraudulent refund requests.

The pattern is always the same: a loop without bounds.

Detection: How Would You Know?

In our scenario, the developer was asleep. But even awake, detection is hard:

What you’d see in logs:

[00:00:02] Bought the dip!
[00:00:02] Bought the dip!
[00:00:02] Bought the dip!
[00:00:02] Bought the dip!
...

By the time you open the terminal, it’s over.

What you’d see on-chain:

  • 33 transactions from the same address in 10 seconds
  • All to the same DEX
  • All for the same asset

But you’d only see this after the fact. No alert system triggered.

The Fix: PolicyLayer Velocity Limits

If this wallet had been wrapped with PolicyLayer, the outcome would be different:

Policy Configuration:

const policy = {
  maxTransactionsPerHour: 5,
  perTransactionLimit: parseEther('1'),
  dailyLimit: parseEther('10')
};

What happens:

00:00:01 — ETH drops to $2,999.

00:00:02 — Transaction 1: APPROVED. Counter: 1/5 for this hour.

00:00:02.1 — Transaction 2: APPROVED. Counter: 2/5.

00:00:02.2 — Transaction 3: APPROVED. Counter: 3/5.

00:00:02.3 — Transaction 4: APPROVED. Counter: 4/5.

00:00:02.4 — Transaction 5: APPROVED. Counter: 5/5.

00:00:02.5 — Transaction 6: REJECTED. Error: TX_FREQUENCY_LIMIT.

Result: 5 ETH purchased (~$15,000). Bug still exists, but $85,000 saved.

The agent throws an error. Your monitoring catches it. You wake up to a manageable problem instead of a catastrophe.

Layered Protection

Velocity limits are just one layer. A production agent should have multiple safeguards:

LayerProtectionExample
VelocityRate limitingMax 5 tx/hour
Per-TransactionSize limitingMax 1 ETH per tx
DailyAggregate limitingMax 10 ETH/day
RecipientDestination controlOnly approved DEXes
Kill SwitchEmergency stopPause all on anomaly

With all layers active, even a catastrophic bug is bounded:

  • Maximum loss per hour: 5 ETH
  • Maximum loss per day: 10 ETH
  • Automatic pause if 3+ transactions fail in a row

Prevention Checklist

Before deploying any agent with wallet access:

  • Rate limits: Max transactions per hour/day
  • Amount limits: Per-transaction and daily caps
  • Recipient whitelist: Only approved addresses
  • Asset restrictions: Only approved tokens
  • Monitoring: Real-time alerts on spending patterns
  • Kill switch: One-click pause capability
  • Testing: Simulate failure modes before production

The Lesson

You cannot test for every edge case in your agent’s logic. Bugs will ship. Models will hallucinate. Loops will run away.

What you can do is make catastrophic failure impossible.

A velocity limit doesn’t prevent bugs. It prevents bugs from draining your wallet.


Related reading:

Ready to secure your AI agents?

Ready to secure your AI agents?

Get spending controls for autonomous agents in 5 minutes.

Get Early Access