2026-10-06 · record inc_0016 · updated 2026-10-19
MakerDAO flip keeper: an unprotected function handed an attacker control of dormant auction winnings
On 6 October 2026 an attacker called a function on a dormant third-party ETH-A keeper that granted a contract of their choosing full rights over the keeper's Vat account. In one transaction they settled four unclaimed 2020 auctions and withdrew 200 ETH. MakerDAO's core contracts behaved as designed.
Third-party ETH-A flip keeperMakerDAO (now Sky)EthereumComponent: Keeper implementation, function with selector 0x8804d1de (unverified source), behind an EIP-1967 proxy
- Event
- Confirmed on-chain
- Root cause
- Independent analysis
- Loss
- Confirmed on-chain
Current status
Funds gone. The adapter contract the attacker created still holds delegation over the keeper's Vat account (confirmed on-chain on 19 October 2026). We found no statement from MakerDAO or Sky, or from the keeper's operator.
Timeline
- 2020-03-12 15:36 UTCThe keeper places the winning bid on ETH-A auction 1457 (50 WETH lot).
- 2020-03-15 15:26 UTCBidding on auction 1457 ends. The keeper never settles it, and three more auctions (1458 to 1460) go the same way, per the analyses.
- 2026-10-06Public alerts appear; CertiK publishes its analysis.
- 2026-10-06 05:57 UTCThe attacker's wallet is funded; its balance goes from zero to about 0.098 ETH in this block.
- 2026-10-06 06:12 UTCThe attacker deploys the helper contract.
- 2026-10-06 06:13 UTCExploit transaction: 200 ETH reaches the attacker's wallet.
- 2026-10-06 06:19 UTCFirst of the 10 ETH deposits to a mixer router.
Root cause
The keeper implementation exposes a function that calls the Vat's hope() on a caller-supplied address and then calls back into that address, without the ds-auth check its other privileged functions carry. Two independent analyses agree. We confirmed the selector is in the implementation and that an unrelated, freshly funded account executed it successfully; we did not decompile the bytecode ourselves.
Basis: independent analysis · verified by us against that source
Classes: Access control and caller trust
Conditions for the exploit
- The keeper still held unsettled claims: four auctions it had won in 2020 where the collateral sat in the retired Flipper, uncollected.
- The keeper's implementation exposed a function that grants Vat rights to any address passed in, and then calls back into that address.
- Auction settlement and collateral exit in the Vat and GemJoin are permissionless once rights are granted, so nothing else had to be bypassed.
- No funding, flash loan or special position was needed. The attacker's wallet held about 0.1 ETH for fees.
How it worked
- The attacker deployed a helper contract, then in one transaction had it create an adapter contract that knew the Flipper, Vat, GemJoin, WETH and the four auction ids.
- The helper called the keeper's unprotected function with the adapter's address. The keeper granted the adapter rights over its own Vat account and then called back into it.
- With those rights active, the adapter settled the four old auctions, which credited 200 WETH of collateral to the keeper inside the Vat, moved it to itself, and exited it through GemJoin.
- The WETH was unwrapped and 200 ETH was forwarded to the attacker's wallet in the same transaction. The rights were never revoked.
A description of the flow for defenders. It leaves out calldata and anything needed to reproduce it.
Impact: loss and recovery
200 ETH of collateral credited to a dormant keeper by four auctions it won in March 2020 and never settled. No MakerDAO core funds were lost, per the analyses we read.
Reported loss
$543K (200 ETH)
USD basis: CertiK, priced at the time of the exploit. The 200 ETH is confirmed on-chain. Earlier alerts rounded the dollar value to about $538K.
Recovered or returned
None reported
No recovery reported. Independent reports say the proceeds went to a privacy mixer in 10 ETH lots; we confirmed the first deposit only.
Method: Native amount from the transaction receipt and the attacker wallet's balance change at the exploit block (200.0 ETH net of gas). The dollar figure is CertiK's, priced at the time of the exploit; other alerts say about $538K. We do not convert prices ourselves.
Loss and recovery are separate figures. They are never netted, and amounts in different currencies are never added together.
Addresses and transactions
Contracts and wallets
- 0x01EB95…BdA5FAwalletEtherscan ↗
Attacker wallet (externally owned)
Ethereum · attacker · Confirmed on-chain · Sent the exploit transaction (nonce 2). Its balance rose by 200.0 ETH net of gas in that block.
- 0xEc997d…321dcFcontractEtherscan ↗
Attack helper contract
Ethereum · attacker · Confirmed on-chain · Created by the attacker in the deployment transaction and is the 'to' of the exploit transaction. Code present.
- 0xf09a13…DCC170contractEtherscan ↗
Adapter contract holding rights over the keeper's Vat account
Ethereum · attacker · Confirmed on-chain · No code before the exploit block, code after, and Vat.can(keeper, adapter) is 1 after the block and today. Creation inside the exploit transaction is per CertiK; we did not trace it.
- 0x9c05a0…0e8273contractEtherscan ↗
Dormant ETH-A keeper (EIP-1967 proxy), affected
Ethereum · victim · Confirmed on-chain · Code present; the implementation slot holds the implementation address below at the block before the exploit.
- 0x68399e…6A5546contractEtherscan ↗
Keeper implementation (source reported unverified)
Ethereum · victim · Confirmed on-chain · Code present and its dispatcher contains the selector 0x8804d1de. Whether the function lacks an access check rests on CertiK and the repository's decompile.
- 0xd8a04F…C15531contractEtherscan ↗
MakerDAO ETH-A Flipper (retired auction house)
Ethereum · protocol · Confirmed on-chain · Emitted four events in the exploit transaction; its record for auction 1457 changed as described.
- 0x35D1b3…A0492BcontractEtherscan ↗
MakerDAO Vat (core accounting)
Ethereum · protocol · Confirmed on-chain · Emitted seven events in the exploit transaction; holds the delegation.
- 0x2F0b23…6B042AcontractEtherscan ↗
MakerDAO ETH-A GemJoin (collateral exit)
Ethereum · protocol · Confirmed on-chain · Emitted one event in the exploit transaction.
- 0xC02aaA…756Cc2contractEtherscan ↗
Wrapped Ether (WETH)
Ethereum · infrastructure · Confirmed on-chain · Emitted two transfers and a withdrawal of 200 WETH (0xad78ebc5ac6200000 wei) in the exploit transaction.
- 0xd90e2f…24F31bcontractEtherscan ↗
Mixer router that received the proceeds
Ethereum · laundering · Confirmed on-chain · Code present; received 10 ETH from the attacker's wallet in the transaction listed. Label from CertiK.
- 0xaDC374…DaF073walletEtherscan ↗
Keeper owner and 2020 operator
Ethereum · victim · Independent analysis · Named by CertiK. Not checked by us.
Transactions
- 0xbb6940…f3a88ctxEtherscan ↗
exploit · block 26,131,471 · 2026-10-06 06:13:11 UTC
Succeeded. 16 events: seven from the Vat, four from the Flipper, one from GemJoin, three from WETH and one from the helper, including a WETH withdrawal of 200 WETH. Attacker balance +200.0 ETH net of gas.
Confirmed on-chain · Read-only JSON-RPC lookup of the transaction, receipt and block · checked 2026-10-19
- 0x4a587a…ad1167txEtherscan ↗
attack setup (helper deployment) · block 26,131,466 · 2026-10-06 06:12:11 UTC
Contract creation; the created address is the helper contract.
Confirmed on-chain · Read-only JSON-RPC lookup of the transaction, receipt and block · checked 2026-10-19
- 0xd4c0b1…048ac6txEtherscan ↗
attacker funding · block 26,131,392 · 2026-10-06 05:57:23 UTC
Per CertiK this was a mixer withdrawal funding the attacker. We confirmed the transaction and that the attacker wallet's balance went from zero to about 0.098 ETH in that block; we did not decode the internal transfer.
Confirmed on-chain · Read-only JSON-RPC lookup of the transaction, receipt and block · checked 2026-10-19
- 0xb8ecff…ebefebtxEtherscan ↗
proceeds (first mixer deposit) · block 26,131,503 · 2026-10-06 06:19:35 UTC
10 ETH from the attacker's wallet to the mixer router. Later deposits are reported by CertiK and SentinelTX and not listed here.
Confirmed on-chain · Read-only JSON-RPC lookup of the transaction, receipt and block · checked 2026-10-19
Explorer links use the chain we confirmed for each item. Where no explorer is configured, or a chain is not verified, we say so rather than guess.
What is verified, reported, estimated or unknown
- verified200 ETH moved from the auction path to the attacker's wallet in a single transaction (block 26131471, 2026-10-06 06:13:11 UTC).Receipt, block and balance change read from a public node.
- verifiedThe Flipper's record for auction 1457 listed the keeper as winner with a 50 WETH lot before the block and was cleared after it.Read-only eth_call at the blocks before and after. Only 1457 was read; the receipt shows four settlement events from the Flipper.
- verifiedThe keeper still grants the adapter rights in the Vat.Vat.can(keeper, adapter) returned 1 after the exploit block and still does on 19 October 2026.
- reportedFunction 0x8804d1de has no authorisation check.CertiK and the repository author's decompile. We found the selector in the implementation and saw an unrelated account call it successfully; we did not decompile it.
- reportedThe implementation source is unverified.CertiK. We did not check the explorer.
- estimateThe loss was about $543K.CertiK's $542,982 at the time; other alerts say about $538K. Dollar values depend on the price used.
- reportedThe proceeds went to a mixer in 10 ETH lots, twenty in total.CertiK and SentinelTX. We confirmed the first 10 ETH deposit only.
- unknownThe keeper's operator knew of the flaw or can recover anything.No statement found.
- hypothesisOther dormant keepers from the same period carry the same flaw.Plausible, since keeper code was often reused, but nothing we read tests it.
Associated code
- Guarded delegation pattern (illustrative)Defensive pattern
- src/test/2026-10/MakerDAOFlipKeeper_exp.solPublic reproduction file — open in the code reader
Public reproduction file
From the public reference dataset
- File
- MakerDAOFlipKeeper_exp.sol
- Path
- src/test/2026-10/MakerDAOFlipKeeper_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Status
- Test or reproduction identified
- Date
- 2026-10-06
- Licence
- file MIT; repository Apache-2.0
- Framework
- Foundry
- What it is
- A public Foundry test that reproduces this incident against archived chain state. ThreatWire has not executed it. Use only for defensive research after your own review.
- Dataset loss text
- exactly 200 ETH (200.000000000000000000 WETH, 0xad78ebc5ac6200000 wei, reproduced with zero variance) to a fresh attacker on Ethereum; the dormant keeper proxy's unprotected drain settled its four undealt 2020 ETH-A liquidation auctions (#1
ThreatWire has not executed this file. Retrieved 2026-10-19 · blob 5be9555d8ad18f75d2935d6778c63357a196efa7.
Remediation and defensive indicators
- No fix, revocation or statement from the keeper's operator or from MakerDAO or Sky was found. The adapter's rights over the keeper's Vat account were still in place on 19 October 2026. (none found)
- Prevention for similar keepers: gate any function that grants Vat rights or calls back into a supplied address, revoke delegations after use, and settle or sweep won auctions. (recommendation)
For developers
- Any function that grants a third party rights over your own account, or calls back into a caller-supplied address, must be gated like every other privileged function.
- Check that every external function either carries the access check or is deliberately permissionless and documented as such. A single missed modifier is enough.
- Retire or sweep dormant contracts that still hold claims on value. A forgotten claim becomes a bounty once any function can reach it.
- Revoke delegations after use (nope in the Vat's case) rather than leaving rights open.
For auditors
- Enumerate the external surface of upgradeable implementations and diff the access modifiers across all functions, including selectors with no verified source.
- Treat 'hope'-style delegation primitives as authority transfers and trace who can trigger them.
- Ask what value a contract can still claim, not only what it holds today.
Defensive lessons from the class
- Authenticate against addresses you control, never against the caller's own answer.
- Validate forwarded senders cryptographically.
Sources
On-chain data
ThreatWire: Read-only lookups of the exploit transaction, receipt, balances, Flipper record, proxy implementation slot and Vat delegation
Published 2026-10-19 · retrieved 2026-10-19 · Public JSON-RPC nodes. No code executed.
Independent analysis
CertiK: MakerDAO Legacy Auction Keeper Incident Analysis
Published 2026-10-06 · retrieved 2026-10-19 · Primary technical analysis: attack flow, addresses, root cause, fund flow.
Independent analysis
Olympix: MakerDAO keeper loss and how it could have been prevented
Published 2026-10-06 · retrieved 2026-10-19 · Same mechanism; adds the timeline of the attacker wallet. Vendor post.
Independent analysis
SentinelTX via ChainBounty: Third-party MakerDAO keeper exploit sends 200 ETH to Tornado Cash
retrieved 2026-10-19 · Call-trace reading of the proxy delegatecall; notes that function names are inferred from selectors.
Media report
The Crypto Times: Dormant MakerDAO keeper drained of $538K, core remains intact
Published 2026-10-06 · retrieved 2026-10-19 · Quotes the first public alert; source of the $538K rounding.
Media report
SlowMist Hacked: MakerDAO ETH-A Liquidation Keeper Bot entry
Published 2026-10-06 · retrieved 2026-10-19 · Incident database entry; loss listed as $538K.
Repository entry
DeFiHackLabs (pinned file): Reproduction file listed for this incident
Published 2026-10-06 · retrieved 2026-10-19 · Repository claim, not proof. Linked to the exact commit for traceability. We did not run it.
- FlashLoopAdapter: a spoofable caller check in a Safe moduleShared class: Access control and caller trust
Method, uncertainty and corrections
Still unknown
- Who operates the keeper and whether they have responded
- Whether MakerDAO or Sky has commented
- Whether other keepers share the implementation
- Where the remaining proceeds are now
Where sources disagree
- Loss in dollars: $542,982 (CertiK) versus about $538K (alerts). The ETH amount is the same.
- The repository file header and some alerts say the keeper's authority was unset; CertiK and the file's own later analysis say the function simply has no check. The mechanism is the same either way.
Verification notes
- Transactions, contracts, balances and the Flipper record were read from a public archive-capable node on 19 October 2026. No exploit code was run.
Written by ThreatWire editorial. Facts attributed to the sources listed; on-chain items are marked as confirmed only where we read them ourselves. Published 2026-10-19, last updated 2026-10-19. Figures are estimates from public post-mortems and named analysts; not independently verified unless marked as confirmed on-chain.
No corrections recorded since publication.