Track 7 · The Breach Lab · lesson 10

The drainer pattern

16 min


Back in track 5 you granted an unlimited approval and I said you would collect it in track 7. Here is the collection.

A drainer is not sophisticated. It is a contract, or just a script, that calls transferFrom on every token a victim has approved, moving the balance to the attacker.

It works because the victim already did the hard part — they signed the approval, willingly, possibly years ago, for a site they no longer remember. The drainer just exercises a permission that was always live.

Two ways in

// What the victim approved, and forgot:
token.approve(app, type(uint256).max);

// What the drainer does, whenever it likes, forever:
function sweep(address victim) external {
  uint256 bal = token.balanceOf(victim);
  token.transferFrom(victim, attacker, bal);  // uses the standing approval
}

An unlimited, un-revoked approval is a permanent transferFrom right. The drainer needs no signature from the victim at attack time — the approval already granted it.

The signature variant

The other form skips even the approval transaction. A drainer site shows an innocent-looking prompt that is actually a permit signature (track 2) or a Seaport order. No gas, no obvious transaction — and the attacker submits the signed authorisation themselves, moments later.

The defence is the same as track 2: read what the wallet is showing you, and be most careful when there is no gas fee attached, because that is the signature case.

Predict

A drainer sweeps a wallet that approved a DEX in 2021. Whose action at attack time made it possible?

Choose one answer

Check

What stops a drainer's transferFrom once you've revoked the approval?

Choose one answer

Worth remembering

  • A drainer calls transferFrom against standing approvals — no attack-time signature needed.
  • It works on approvals the victim granted long ago and forgot.
  • Bounded approvals cap the loss; revoking to zero closes it entirely.
  • The signature variant tricks the victim into signing a permit or order instead.
  • Revoking is the only on-chain action that actually removes the permission.