BlockWatchdog (@BlockWatchdog) header
BlockWatchdog (@BlockWatchdog) profile picture

On-chain forensics on hacks, rugs & drainer campaigns. Custom tooling, human analysis. πŸ›‘οΈ How not to get drained. DMs open.

tx graph
Joined July 2026
Photo by BlockWatchdog (@BlockWatchdog)
Most crypto isn't lost to "hacks." It's lost to approvals people sign themselves. Here's how wallet drainers actually work β€” and how not to be next 🧡
16
1
14
2,270
THEO: 219M minted, not 19M Three mints across Base and Robinhood Chain; only the first was reported. Proceeds are 298.94 ETH (~$752K), not 700.8. The wallet already held 400.79 ETH before the first sale. The second mint on Base, 100,000,000 THEO, 38 minutes after the first: basescan.org/tx/0x8c8dc4d6ae… ADDRESSES Seller: 0x3048b4Ee5A070F33b73E3401829847255079E0AD Holds the unsold 190.95M: 0x690d7552375fcd23bd2a5e1d74f7445fadfc6c83 THEO on Base: 0xebE516a20238F79DC20b07eaD6768e08891Ed309 THEO on Robinhood Chain: 0x3Dc751e0dA01812E6D9143cC696e7f07eA94dA48 Hydrex THEO/USDC pool: 0x182BE47742B81777055d69c50E5C9d2fE803e938 THREE MINTS (Oct 12, UTC) 17:06:59 Base 19,000,000 THEO 17:42:50 Robinhood Chain 100,000,000 THEO 17:45:03 Base 100,000,000 THEO All three went to the seller. THEO supply on Base went from 54.32M to 167.40M. WHERE 700.8 ETH COMES FROM PeckShield's alert says the 19M were swapped for 700.8 ETH, and every outlet repeated it. That figure is the wallet's balance on Ethereum, not what THEO sold for. - Balance at block 26177652, before any sale: 400.79 ETH - Arrived from Base and Robinhood Chain via Relay: 278.52 + 11.21 + 8.78 + 0.43 = 298.94 ETH - Balance now: 700.81 ETH, unmoved The 400 ETH were there a week earlier: 414.4 ETH landed on Oct 5. WHAT WAS ACTUALLY LOST The Hydrex pool held 707,944 USDC at block 52518012. 38 blocks later it held 233.55. Four sells, 58 seconds, 19.0M THEO. That pool was the only real money on Base, and it bounds the damage there. On Robinhood Chain 2.56M THEO fetched 8.70 ETH. ONLY 12.8% WAS SOLD 28.05M of 219M THEO were sold. The other 190.95M went to one address on both chains, 11 seconds apart, and have not moved: - Base: 93,510,011 THEO - Robinhood Chain: 97,440,652 THEO The accounting closes to the token on both chains. HOW THE MINTS GOT THROUGH THEO on Base and Robinhood Chain is a Hyperlane synthetic of the Autheo mainnet coin. Both routes are secured by a TrustedRelayerIsm: one EOA per chain, no validator signatures. Every delivery carries empty metadata. - Base relayer: 0xeF305Ec5DF4054B15295A0389787bf671Ab930CE - Robinhood Chain relayer: 0x8c364589ceA8a7B29C2058DD6728319E32D47c94 The relayers do not look hijacked. The three messages (origin nonces 474, 561, 564) were delivered in the normal queue, between 61 ordinary user transfers, by the same keys. So the question moves to Autheo mainnet: either 219M THEO were created there, or they were sitting in a wallet someone got into. IT WAS REHEARSED 20 minutes before the first mint the same wallet bought 2,342 THEO on Base and bridged 250, then 25, back to Autheo. Two test transfers, then 19M came the other way. From the first test to 278.52 ETH on Ethereum: 33 minutes. WHAT IS NOT ESTABLISHED - The root cause. Autheo's three mainnet RPCs and its explorer were returning HTTP 520 when I checked (09:27 and 09:36 UTC, Oct 13), so the origin side cannot be read. - Whether 0x690d…6c83 belongs to the seller. It is an old, active wallet that bought 15,364 THEO from the pool 50 seconds before receiving 93.5M. - Whether the 400 ETH already in the wallet are connected to anything. Every figure above is a balance read or a receipt at a named block. Check them.
1
165
Neutron's governance was bought 11 minutes before the vote closed. One wallet voted YES with 100 NTRN staked, then bought 31.62M NTRN for $20,199 and staked it. Without it, the proposal fails quorum and threshold. mintscan.io/neutron/tx/71FB9… The proposal Prop #9, "AIATO: AI Agent Takeover", was framed as an AI-governance research experiment citing an arXiv paper. Its payload was 11 MsgUpdateAdmin calls moving admin rights from the Neutron gov module to one address: six Astroport pairs, Astroport Staking and Treasury, two Drop (dATOM) contracts and a Neutron investor vesting contract. It ran expedited: 3 days, 67% threshold, 30% quorum. It was rehearsed in public. On Aug 24 the same address ran the same contract list as "TestProp: Preparation for AIATO". It got 2.9% YES. The vote At 02:13:10 UTC Sep 22 the wallet staked 31.62M NTRN bought minutes earlier, mostly from the Astroport NTRN/USDC pool that was drained an hour later. Bonded NTRN jumped from 105.24M to 136.86M. β€’ With it: 81.9% YES, 33.3% turnout. Passed. β€’ Without it: 40.8% YES, 13.3% turnout. Fails on both counts. At $0.000288 per NTRN, the entire bonded stake was worth ~$39K. It administered contracts holding ~$10.4M. The link Four days earlier the proposer's Cosmos Hub address sent 1 ATOM to the staker's Hub address. Four minutes later that key made its first 100 NTRN stake and cast its YES vote. What was taken (prices at 02:40 UTC) ~$10.39M: 1.59M dATOM ($4.16M), 1.72M ATOM ($3.13M), 2.85M USDC, 804K DYDX, 20 WETH, 16 wstETH. DeFiLlama carries $4.9M. Where it is β€’ ~$5.9M never left Neutron. The IBC rate limit blocked 1.67M USDC and 14 WETH 14 times before the chain halted at 07:43 UTC. β€’ 1,227,121 ATOM sat on the attacker's Hub address when the Hub halted at block 33,086,740, 11:18 UTC. β€’ ~260K ATOM left earlier through deposit-style addresses. β€’ On Ethereum the accounting closes at 694.6 ETH, and none of it has moved: 671 ETH in 0xef6c5a31df984c8569236a0abc1f27580e2a5d54, 23.59 ETH in 0xe149310eb8b1b3d9c471ccd81819d393621fba5c. Addresses Proposer: neutron1dd25c4sshelrpfs0433apg24c5phrhk8l6n605 Late staker: neutron1ekgfga6vv4zdrrjn3dux6f62fuzektfndgaehm Drainer code: code_id 5399, uploaded by the proposer at 01:18 UTC, an hour before the vote closed.
1
170
🚨 The Fetch.ai exploit has a fourth victim nobody has named: World Mobile. 500,529,231 WMTX minted through its own converter, 03:38-04:36 UTC. Different company, different multisig, no shared signers. Same compromised signing pattern. etherscan.io/address/0x63bbc… This is the part that stops being a Fetch.ai story. World Mobile's converter is 0x63bbc71c, a TokenConversionManagerV2 β€” the same contract family as the Fetch.ai V3 and the SingularityNET v1. Its owner is a 3-of-4 Safe at 0x9369334c. I pulled the signer list on both multisigs and compared them: zero overlap. Two unrelated organizations. What they share is the shape of the key that broke. Three signing keys, all with nothing behind them FET authorizer 0x69e5446b β€” nonce 0 AGIX authorizer 0x69697dac β€” nonce 0 WMTX authorizer 0x09578799 β€” nonce 0 None of the three has ever sent a transaction. A signer address that has never transacted is not sitting in someone's hardware wallet β€” it exists to be called by a server. Three separate projects, three keys that live in backends, all three producing valid signatures for the same attacker on the same night. That is the dependency worth naming. Not the contract. How the WMTX leg ran 504 mints, 03:38:23 to 04:36:11. 500 of them exactly 1,000,000. The recipient nets 997,000 per call, not 1,000,000 β€” the missing 3,000 leaves in two 1,500 fee transfers to 0xe7b81ea2 and 0x48b21074. So the per-call figure is the cap, less a 0.3% fee. Same signature as the AGIX leg: a long run of identical maximum-size calls is what a binding limit looks like from outside. WMTX totalSupply went 1,027,930,149.42 to 1,494,037,869.44. Up 466,107,720, a 45.3% increase, net of the conversions burning in the other direction. Converter balance now: zero. V2 kept the brake that V3 dropped conversionIn on this contract carries checkLimits(amount), nonReentrant and notZeroAddress. The Fetch.ai V3 version of the same function carries only notZeroAddress. That is why the WMTX leg needed 504 transactions and the FET leg needed one. The regression is specific to V3. Anyone auditing this family should diff conversionIn across versions before anything else. The number that is still open V2 enforces a maxSupply, set to 2,000,000,000 WMTX. Supply is at 1,494,037,869. 505,962,130 WMTX are still mintable, and the authorizer that signed all 504 calls has not been rotated. The minting stopped at 04:36. Nothing on-chain made it stop. Do not print the notional The two collector wallets hold 398,577,793 WMTX between them. At screen price that reads $6.45M. Total WMTX liquidity across every pool on every chain is $470,366, and most of it is the WBNB pair on BSC, not Ethereum. The realizable number is bounded by that, not by the balance. This is the third time tonight the same trap has been set. The NTX mint was reported at $462,730 against $27,400 of liquidity and returned $42,367. Read the pools, not the balance. There is a fifth Collector #2 also received 492,397,101 CGV, Cogito Governance Token, minted straight to it. Total CGV liquidity: $37. Nothing to realize, which is presumably why half of it was moved on rather than sold. Where the money actually is collector #1 0x2dcc1085fdcf418b421e45e86e4e54637cc21dfe β€” 632.92 ETH collector #2 0x83f4424a401a9bb75f90314f21adaea6a9ce09c5 β€” 83.88 ETH 716.80 ETH between them, unmoved. The FET leg alone accounts for 522.78 of it. Four token mints across three converters produced less than the single swap that started the night. Addresses WMTX token β€” 0xdbb5cf12408a3ac17d668037ce289f9ea75439d7 WMTX converter β€” 0x63bbc71c034bc99a905d5594df985c218a35d392, V2, emptied WMTX authorizer β€” 0x09578799fd680ffbafd3c84276d598cd3b0ac9c1, nonce 0, unrotated WMTX owner Safe β€” 0x9369334cc21f445731201eca008419751e4e9e5d, 3-of-4 CGV token β€” 0xaef420fd77477d9dc8b46d704d44dd09d6c27866 Verified at block 26,016,886, 06:19:47 UTC.
2
7
1
25
1,938
🚨 Fetch.ai/NuNet, hour 7: a third converter is minting right now. Every root-cause writeup tonight describes one contract. A second signing key was draining AGIX while they published. 140,000,000 in 14 calls, 03:13-03:17 UTC. etherscan.io/address/0x2dcc1… Credit first. PeckShield had the FET drain and the same-attacker link. SlowMist published the root cause: conversionIn() treats one EOA signature as the whole authorization, carries no burn or lock proof, and lost the checkLimits(amount) modifier that conversionOut() still has. That is correct and it is theirs. It is also scoped to one contract and one protocol. Here is what sits outside that scope. It is still running 03:13:35 UTC, six hours after the NTX mint, a different compromised wallet started calling conversionIn on the AGIX converter. Fourteen calls, exactly 10,000,000 each, last one 03:17:35. 140,000,000 AGIX, minted rather than transferred β€” that converter holds MINTER_ROLE on the token and its own balance never left zero. The signature on those calls recovers to 0x69697dac8ba57aa7213631133f1ea743d52e6a36, that converter's registered authorizer. A second signing key, not the FET one. Why fourteen calls and not one? The older converter still carries checkLimits on conversionIn, perTxnMaxAmount 10,000,000. The attacker is hitting the cap every time. Same codebase, two versions: the newer one dropped the brake and lost 8.72x the cap in a single transaction. The brake does not stop a key holder β€” it is just the only reason anyone got four minutes of warning. Selling started 03:19:47. As of 03:28:47: 5,700,000 AGIX sold for 27.44 ETH, $72,373, at roughly 17% of screen price. 40,000,000 more was just split across three wallets with zero outgoing history. 94,300,000 still sitting. Not two protocols. A keyring At least five operational keys and two signing keys from the same 2019-2021 deployment family. The NTX deployer, dormant since 2023-03-20, woke at 19:36. A NuNet LP wallet last used 2026-08-31. An ops wallet silent since 2025-05-05. A wallet dormant since 2022-01-06. A distribution operator still in service β€” that is the one minting AGIX now. All of them moved inside 80 minutes. One note on attribution: 0x1572f2af, listed in the alerts as the attacker, added NTX liquidity in November 2021 and was managing Uniswap V3 positions on 2026-08-31. It is a compromised wallet, not the attacker's own. Neither signing key has ever sent a transaction. A signer with a zero nonce does not live on a hardware wallet. It lives in a backend, and that is where this started. The mint landed exactly on the documented cap NTX totalSupply before: 591,467,121.866548 NTX totalSupply after: 1,000,000,000.000000 To six decimals. The published tokenomics say 1,000,000,000 NTX fixed, "with no new tokens ever minted", split across Ethereum and Cardano and held constant by 1:1 conversion. The attacker minted 408,532,878.133452 β€” exactly the gap to that number, which under NuNet's own cross-chain invariant is the Cardano float. Anyone spot-checking totalSupply against the whitepaper would have read 1,000,000,000 and moved on. Real aggregate supply is now about 1.41 billion. The contract is an uncapped OpenZeppelin ERC20PresetMinterPauser. Trillions were on the table. They stopped on the number that looks right. NuNet cannot undo any of it NTX DEFAULT_ADMIN_ROLE β€” compromised EOA, sole holder NTX MINTER_ROLE β€” compromised EOA, still granted NTX PAUSER_ROLE β€” compromised EOA, sole holder NTX paused() β€” false NuNet converter owner β€” compromised EOA, a second mint path FET conversionAuthorizer β€” unrotated, same key that signed the drain AGIX conversionAuthorizer β€” unrotated, minting eleven minutes ago The only address that can grant or revoke roles on the NTX token is the one the attacker took. It is also the only PAUSER. There is no admin recovery path in that contract. AGIX and FET token roles sit behind a 3-of-N Safe and were never exposed. NuNet's sat on a single 2021 deployer EOA. Same ecosystem, same contract family, and the gap between those two decisions is the whole incident. That Safe is the one actor who can still act β€” rotate both authorizers, revoke the AGIX converter's MINTER_ROLE. It has not transacted since early September. What the market actually paid The 408.5M NTX mint was reported at $462,730. Total NTX liquidity across every pool before the attack was $27,400, with 5.24 WETH of quote-side depth. 447,554,414 NTX dumped over six hours. Realized: 8.0925 ETH + 0.1665 WETH + 20,586 mUSD = $42,367. The headline is 11.0x the money. The FET leg is where the value was: 522.78 ETH on one swap, $1,378,688. The people paying are not the protocols. 591.5M NTX held by everyone else went from $0.00131 to $0.00044. $513,202 of holder value destroyed to extract $42,367. Twelve to one. AGIX is the same trap. 140,000,000 minted reads as $10.4M at screen price, against $250,978 of liquidity on the entire token, and the first 5.7M cleared at 17%. Do not print the notional. Addresses attacker β€” 0x2dcc1085fdcf418b421e45e86e4e54637cc21dfe, 576.62 ETH NTX deployer β€” 0x863f13e5b505f1eb17803b94ec9d3daf80092165, admin+minter+pauser LP wallet β€” 0x1572f2af7696b39c85e3221cde8efb640f86c362, compromised, not attacker ops wallet β€” 0xa7a31d206042b8a3e81aa4cf8c68c1b76856ee48, owns NuNet converter distributor β€” 0x2ddf758aa234a2dc76ea19a133d131d82ae63b3a, minting AGIX FET authorizer β€” 0x69e5446b07b23de0a76730062c3252152216c85c, zero nonce AGIX authorizer β€” 0x69697dac8ba57aa7213631133f1ea743d52e6a36, zero nonce FET converter β€” 0xab424a430cc09864fa1277a38193111705adf3a3, emptied AGIX converter β€” 0x611192364cc6962f433a5dc52cd500a423dd7be4, minting NTX token β€” 0xf0d33beda4d734c72684b5f9abbebf715d0a7935 owner Safe β€” 0x02ee7cddc3bdda9e571b5994d1adfa69b5ed4335, 3-of-N, silent Timeline, UTC 19:34-19:38 β€” ETH and NTX swept from five dormant and operational wallets 20:21:47 β€” 8,721,530.40 FET, one conversionIn, converter to zero 20:24:11 β€” FET sold for 522.78 ETH 20:41-20:42 β€” Uniswap V3 LP pulled, two SingularityAirdrop contracts emptied to the wei (6,134,102.489543 + 2,949,449.051075 = 9,083,551.540618 NTX) 20:49:35 β€” deployer, swept to zero at 19:36, funded with 0.000028 ETH for gas 20:50:11 β€” 408,532,878.133452 NTX minted, supply hits 1,000,000,000.000000 02:27 β€” NTX dumping ends, 447.5M sold 03:13:35 β€” AGIX minting begins 03:17:35 β€” 140,000,000 AGIX 03:19:47 β€” AGIX selling begins 03:25-03:26 β€” 40,000,000 AGIX staged across three fresh wallets State verified at block 26,016,034, 03:28:47 UTC. Every line is one eth_call or one log query. Check them.
3
3
1,385
Nostra's $3.53M oracle hack cost about $15 to set up. The attacker never bought NSTR's price up. He seeded a decoy band at $99 with 190 NSTR and zero SolvBTC, burned every position around the real price, then swapped 0.000008 NSTR. All times UTC, 17 Sep 2026. The venue is Ekubo's NSTR/SolvBTC 0.01% pool β€” a real pool with ~$116K of liquidity, indexed by GeckoTerminal. THE SETUP β€” four transactions, twenty minutes 05:27:47 β€” mints an LP position around the honest price, ticks -16,369,800 / -16,363,400, funded with 1,900 NSTR + 0.00015148 SolvBTC. Pool price 7.81e-8 SolvBTC per NSTR, i.e. $0.006. 0x6e7625b674c8ec9f7f92fffdf9866f9efcaae416dea17039796bed9ad95f4eb 05:31:33 - 05:43:01 β€” five wash swaps, buy 838 NSTR / sell 700 NSTR, repeat. The price does not move; the volume does. Pragma's NSTR/USD entries carry GeckoTerminal's own 24h volume in a field, and it climbs 30 -> 54 -> 62 across exactly this window. This is him clearing GeckoTerminal's indexing threshold, nothing else. 05:41:58 β€” mints a second position at ticks -6,645,400 / -6,645,200, which is 1.3e-3 SolvBTC per NSTR, or $99. It costs 190 NSTR and zero SolvBTC, because a concentrated range sitting entirely above spot only ever needs token0. $1.13 of decoy. 0x5bd5af80c41129f64c4cb1289dd498fb04b8b3179d51bcb6b68e086c9a39a47 05:45:33 β€” burns the first position, withdrawing 1,113.26 NSTR + 0.00021288 SolvBTC. There is now no liquidity anywhere near the real price. Only the decoy band remains. 0x51ebb665f249a6ec863ccadfe42aaacc4e41956cb6ea08cb3d346c4f3e5e89c 05:47:19 β€” swaps 0.000008 NSTR for 0.00000001 SolvBTC. With nothing in between, the pool teleports from 7.81e-8 to 1.2999926e-3. A 16,645x move on a dust trade. 0x772e73613ffbc845508377fc6ded1137f60ad730aecb2b7c18a2978a84a6ac1 Check it two ways: sqrt_ratio_after = 0x93aed69a93cfef533cbbff71ad42b76, so (x/2^128)^2 = 1.2999926e-3; tick_after = -6,645,400, so 1.000001^tick = 1.2999926e-3. Same number. Net cost of all thirteen transactions: -2,767.19 NSTR (~$16.52), +0.0000281837 SolvBTC (+$2.15), 12.417 STRK of gas. About $14.72. WHY THE ORACLE BELIEVED IT 05:47:48, 29 seconds after the dust swap, Pragma's GECKOTERMINAL publisher writes NSTR/USD = $99.02439975. 05:47:54, block 14,999,429, Nostra's price feed flips from 0.00000245 ETH to 0.02032399 ETH and stays there for 59 minutes 29 seconds. But Nostra quoted $49.5152, not $99.02. Pragma's median ran over only two entries inside its 60-minute freshness window β€” GECKOTERMINAL $99.02439975 and AVNU $0.00596118, timestamped 05:37:08 β€” and a two-element median is a mean: (99.02439975 + 0.00596118) / 2 = 49.515180 Nostra's feed read 0.02032399 ETH against its own ETH/USD of $2,436.29119518 = $49.51516. The two agree to 4e-5 percent. The honest source didn't protect anything; it halved the error. The third source was there and should have saved it. DeFiLlama publishes NSTR/USD every ~30 minutes, but its last observation was timestamped 04:25:06 β€” 82 minutes 42 seconds old, outside the window. A median of three would have been $0.00596118, and there would have been no incident. Pragma described this exact arithmetic in its own post-mortem of the Vesu incident 13 days earlier: three USDT observations aged out, leaving Bitstamp at $0.99995 and a broken Ekubo-derived $3.073203, median $2.036576. The committed fix β€” a default minimum of four accepted sources β€” shipped for USDT and USDC. NSTR/USD was still a two-source feed on the 17th, and per Nostra's own docs NSTR has no fallback oracle at all. WHAT WAS BORROWED β€” 05:48:53 to 05:51:35 939.386010 ETH $2,288,617.87 28,272,985.9088 STRK $797,024.16 2.88 WBTC $219,486.71 113,661.6914 USDC.e $113,538.01 84,377.3292 USDT $84,212.20 29,078.9429 DAI $29,044.03 $3,531,922.97 Priced on Nostra's own feeds at the incident block. Against 294,177.608 NSTR of collateral, worth $1,755.92 at the honest price. 2,011x. That collateral was not bought for the occasion. The position opened on 15 Jan 2026 with 111 NSTR and grew for eight months β€” but it went from 186,389 to 294,157 NSTR on 14 Sep at 11:55:18, 66 hours before the exploit. The wallet that ran the pool manipulation is separate and was first active between 7 and 13 Sep. No transfer has ever linked the two; the link is 65 seconds and the fact that neither leg works alone. WHERE THE MONEY IS, as of 18 Sep 05:20 Still on Starknet, untouched since 15:34 on the 17th: 475.386010 ETH, 11,872,441.27 STRK, 9,078.94 DAI, 0.360494 WBTC β€” about $1.58M. On Ethereum: 234.5698 ETH and 1,347,821.45 DAI, about $1.93M. PeckShield reported that DAI as bridged; it was 1,348,340.56 native USDC sent out over Circle's CCTP v2 and turned into DAI in five CoW Swap batches on the L1 side. The 234.57 ETH is 7.43 WBTC that went out through StarkGate and was sold on CoW at 12:33. 19 ETH has already been round-tripped through Railgun, 12:25 to 13:36. That is a test tranche; the rest is sitting. 2.2M STRK went to two fresh Starknet addresses of the same account class. Outstanding debt has accrued to roughly $3.65M against $1,628 of collateral. The money market is paused. ADDRESSES Borrower, Starknet 0x6d48ef7ab62c26e3ef1987c322096cd508e9034c82048783a6b438fc1344bc3 Pool manipulator, Starknet 0x2d9fb4edec9d5c015c43514ca5a309aab1b2638c3a45ad750d09ee971d0da23 Cash-out, Ethereum 0xa059aaab82773caf622de9d9a0f2dbf9aa7f3c37 Pragma oracle 0x2a85bd616f912537c50a49a4076db02c00b29b2cdc8a197ce92ed1837fa875b Nostra NSTR price feed (also serves LORDS and UNO) 0x683852789848dea686fcfb66aaebf6477d83b25d8894aae73b15ff19b765bf0 The publish that did it: starkscan.co/tx/0x6bc9b41bce…
3
3
12
976
Links, in order. The dust swap that moved the pool 16,645x starkscan.co/tx/0x772e73613f… The decoy band, 190 NSTR and zero SolvBTC starkscan.co/tx/0x5bd5af80c4… Burning the position that held the real price starkscan.co/tx/0x51ebb665f2… First borrow, 939.386 ETH, 65 seconds after the feed flipped starkscan.co/tx/0x2460fde607… The cash-out address on Ethereum etherscan.io/address/0xa059a… Pragma's own post-mortem of the 4 Sep Vesu incident, where the same median-of-two produced $2.036576 for USDT pragma.build/updates/vesu-in…
121
The "$7.8M rsETH exploit" hit a $144M Aave loop β€” and the attacker took exactly the room it had left. 2,900 rsETH moved the Safe's health factor from 1.0587 to 1.0012. The attacker's only paid haul came 69 minutes later, from a second Safe. The victim, 0x40e93a52…aba8, held 53,402 aEthrsETH against $129.4M of WETH debt. Aave only lets aTokens move while HF stays β‰₯ 1, so the take was capped by collateral Γ— 0.95 βˆ’ debt β‰ˆ $7.99M. The attacker took 98% of it. Blockaid named the path: a publicly callable keeper multicall steered the Safe's Uniswap v4 LP module into an attacker-made pool (the fake token is literally called "Permissionless Attacker Token"). What happened next: Yoink didn't copy the exploit. The attacker's contract paid whoever called it, and the bot called it one block after the attacker's own prepare(). Kelp has since frozen the bot's 2,882.37 rsETH until Sep 16 05:25 UTC. The modules stayed enabled for 81 minutes. Four more parties drained the leftover headroom in 50, 9.5 and 0.5-rsETH bites, down to HF 1.00000. Then Yoink liquidated the victim: 168.83 WETH repaid, 157.707 rsETH seized. Accounting closes to the wei: 53,402.655 βˆ’ 2,966 drained βˆ’ 157.863 liquidated = 50,278.79 aEthrsETH left. The attacker walked away with none of the rsETH. At 05:47 UTC the same multicall emptied Safe 0x6a1fac6b…7ea2: 86,631.95 DUSD + 38,248.16 USDC (~$128.8K), sold for 23.69 ETH, and 23.6 ETH went into LI.FI. Gas was funded from Railgun. Four Safes ran on this keeper contract. Two were hit. Addresses Attacker: 0x0dc2c5d6b05a317076cf501f7e7be36a5dfe9b66 Keeper multicall: 0x4f0055926c839d1d960a82cbf84e2ee933958ebc Victim 1 (rsETH loop): 0x40e93a52f6af9fcd3b476aedadd7feabd9f7aba8 Victim 2 (DUSD/USDC): 0x6a1fac6b3466e29421f70d6eaa91a0de0f627ea2 Yoink proceeds (frozen): 0xc70f00cd7e461686b04b0e912e309beca8b80ea0 Evidence Exploit (Yoink): 0x0e7680b06cb8a6f86c149d9ba90d98e3d334e7b072dde03909d43fcfd98a8705 Liquidation of victim: 0xe77f7513547d917e86e2ac8457b00e9f4336fee3908b9a674095603d467cde66 Second Safe drain: 0x850342386d7446e3ce479ecc246e843961a46fa6540d279a5ef602d14deb547e Modules disabled: block 25980931, 06:00:11 UTC Liquidation of victim: etherscan.io/tx/0xe77f751354…
2
176
Liquid: Blockstream agreed to the return at 03:16:04 UTC. 93 minutes later the chain stopped producing blocks. It has not produced one since. The agreement is a PGP signature in an OP_RETURN. It verifies against Blockstream's key. Nobody has to take my word for any of this. Every claim below is a command you can run. ━━━━━━━━━━━━━━━━━━━━━━━━ THE NEGOTIATION, AND WHICH HALF OF IT IS REAL Three messages arrived at the attacker's address from a single sender, bc1qn8mgsmxx42j3fflqfkh0cqhdd6mj4h9q2mfqym. Two of the three carry a PGP signature. Both verify against the key published at blockstream.com/pgp.txt β€” fingerprint 1176 542D A98E 71E1 3372 2EF7 4AC8 CC88 6844 A2D6, "Blockstream Security Reporting". 19:31:47 UTC blk 965822 "Please contact [email protected]" (unsigned) 01:49 blk 965865 detached PGP signature + an encrypted blob SIGNATURE OK 03:30:05 blk 965875 clearsigned "Yes, thank you." SIGNATURE OK Because all three came from the same address, the first one is now authenticated too. It had been an assumption. It is not any more. The attacker's side, spending from the consolidation address: 18:30:10 UTC blk 965818 "we are whitehats. contact us on chain" 02:20:18 blk 965869 "sending most back to bc1qdlld6…, is that ok" 03:30:05 blk 965875 "Please fix the bug first. The chain is under risk at latest commit right now. Make sure every node is patched. Then we will transfer the money back safely after confirming the fix." + a PGP message encrypted to Blockstream's real subkey BB332D31CBA44EDF Blockstream's signature on "Yes, thank you." was made at 03:16:04 UTC β€” between the attacker's question and the attacker's reply. That is an answer to "is that ok", and the answer is yes. The 01:49 blob is Electrum BIE1 ECIES, encrypted to the public key recovered from the attacker's own spending signature. 101 bytes: 4 magic, 33 ephemeral pubkey, 32 HMAC, 32 of AES-CBC. Whatever Blockstream said privately is at most 31 characters long. ━━━━━━━━━━━━━━━━━━━━━━━━ THE SIGNAL HANDLE IS NOT PART OF THIS CONVERSATION At 20:38 UTC an OP_RETURN reading "Please contact us on Signal @m671aw.70" was paid into the attacker's address. It is unsigned. It came from bc1q7le6nr37p892jzlyugr5sl29pfcg27xl77eafu β€” a two-transaction throwaway holding 0.00100893 BTC β€” and not from the address that carried Blockstream's two verified signatures. It burned a 31,800-sat fee, roughly twenty times what the real messages paid. It is inbound, unsigned, and from a stranger. Treat it as such. It is not alone. The same address has been pelted for a day with a memecoin contract, a Monero swap desk offering to launder "$700M+", a referral link advertising itself as "the biggest one to launder money", a wallet vendor running four different ad creatives, and a New York lawyer offering pro bono counsel for a clean return. The attacker has answered none of them. ━━━━━━━━━━━━━━━━━━━━━━━━ WHAT ACTUALLY LEFT: 3,996.01834922 BTC The figure in circulation is 4,019 or 4,002. Both are the transaction, not the theft. 8db751a650ae2f12006b7e8c69a75e4df360e8afd6b9e05ae0b9fa6458a7b140, block 965783, 2026-09-06 14:28:56 UTC, 83 inputs, 13 outputs. Ten outputs are change to the federation. Three are payments: 3996.01834922 β†’ bc1qgslsydz56d0ed6827hdemfmk5w2f6ldyc6wt7p 2.65138358 β†’ bc1qkxwva32eh7mgezq5kladncd3n5wtcjmslh98my 3.99601658 β†’ bc1qk3cvk5599nydy8zwavlxaduke54pgf4vl0ckru I spend-traced all three. The second and third go to unrelated clusters and never touch the attacker's wallet. They are ordinary customer withdrawals. The functionaries batched a fraudulent peg-out into the same Bitcoin transaction as two real ones, which is exactly why nothing looked wrong at the time. The first output moved on in the same block. 85d2ca15… forwarded 3,995.99999857 BTC to the consolidation address and split off 0.01834922 BTC to a side address β€” leaving a round 3,996 BTC, less a 143-sat fee. Somebody wanted a clean number. The consolidation address shows 15,993.99 BTC of inflow. That is one pile counted four times: it paid itself in blocks 965783, 965818, 965869 and 965875, attaching a new message each round. Read the page cold and you overstate by 4Γ—. It holds 3,998.49854728 BTC and has not moved. ━━━━━━━━━━━━━━━━━━━━━━━━ THE KEYS WERE NEVER THE PROBLEM I decoded the witness on all 83 inputs. Every one is identical: eleven signatures against the 11-of-15 functionary branch. The witnessScript hashes to the scriptPubKey, so there is nothing to argue about. OP_11 <15 pubkeys> OP_15 OP_CHECKMULTISIG OP_IFDUP OP_NOTIF 8064 OP_CSV OP_VERIFY OP_2 <3 emergency pubkeys> OP_3 OP_CHECKMULTISIG OP_ENDIF The emergency branch β€” the 8,064-block timelock and the 2-of-3 recovery keys β€” was never touched. No key was stolen and no key was abused. Eleven honest signers approved a withdrawal that had been made to look valid one block earlier, on the other chain. ━━━━━━━━━━━━━━━━━━━━━━━━ THE HALT WAS TWO EVENTS, NOT ONE "The sidechain is paused" describes the first one. It does not describe what happened this morning. 00:16:10 UTC Liquid block 4050959 β€” the last user transaction. From here, 273 consecutive empty blocks. This is the bridge-node shutdown. 04:49:10 UTC Liquid block 4051232 β€” block production stops entirely. As of 06:42 UTC that is 113 minutes without a block on a chain that mints one every sixty seconds. Three probes twenty seconds apart returned the same tip. The empty-block run needed a baseline, so I took one: across the 2,160 blocks of the thirty-six hours before the incident, the longest natural run of empty blocks was 43. The current run is 273 and it is a different animal. Note the order. Blockstream's signature: 03:16:04. Block production stops: 04:49:10. Ninety-three minutes. Sequence is not cause and I am not claiming it is β€” but the signers were stood down after the agreement, not before it. Also worth keeping: the first stage arrived 9 hours 47 minutes after the Bitcoin left. The federation kept paying ordinary peg-outs for 2 hours 20 minutes after the drain. ━━━━━━━━━━━━━━━━━━━━━━━━ THE BOOKS BALANCE. THAT IS THE PROBLEM. The federation reserve held 4,205.29404448 BTC before the drain. It holds 197.47187814 now β€” 4.70% of what it had. Now ask an explorer whether L-BTC is backed: L-BTC supply, before 4,205.01883617 reserve 4,205.29404448 L-BTC supply, after 197.29721457 reserve 197.47187814 Fully backed at both ends, to the fourth decimal, with the same small surplus. Anyone running the obvious solvency check sees a healthy peg. The check is broken, and it is broken by design. L-BTC amounts are confidential, so no explorer can sum the UTXO set. Supply is derived as peg-ins minus peg-outs minus burns. The counterfeit L-BTC was destroyed by the peg-out that stole the Bitcoin β€” so it passed through the burn counter as if it had been legitimate. The identity that is supposed to expose a shortfall is the thing that absorbed it. The two nodes disagree by exactly 4,007.82183916 BTC of peg-outs. That resolves into 4,002.66609035 (the drain) + 4.14039943 + 1.01571202 (two ordinary batches afterwards), closing to 0.00036264 BTC. No leg is missing. ━━━━━━━━━━━━━━━━━━━━━━━━ TWO NODES, TWO OPINIONS ABOUT WHAT IS TRUE The explorers disagree, which has been reported. Where they disagree has not. Query the same three objects against both: Liquid block 4050336 blockstream 200 mempool 404 tx c652a104… (the mint) blockstream 200 mempool 200, "confirmed": false tx ce4caece… (the peg-out) blockstream 200 mempool 404 mempool.space's node is holding the transaction that created the money in its mempool, as unconfirmed, sixteen hours on β€” while returning 404 for the block that contains it. It accepted the transaction under its relay policy and refused the block. The split is at block validation, not at relay. And that node is alive, not crashed: it is serving a 460-transaction mempool. Its chain tip is frozen at 4050335, one block before the mint. ━━━━━━━━━━━━━━━━━━━━━━━━ WHAT I CANNOT TELL YOU How much was minted. c652a104… has 64 confidential inputs and 5 confidential outputs and a 479-sat fee. Only what left the peg is visible: 3,996.01834922. If counterfeit L-BTC is still sitting in that wallet, it is a second claim on a 197-BTC reserve, and it is frozen only for as long as the chain is. Which bug. Elements shipped a cluster of confidential-value soundness fixes on 1 September, and they reached the production branch on 6 September at 17:20:55 UTC β€” two hours and fifty-two minutes after the money was gone. One of them, buried in a PR titled after RPC error handling, made peg-out authorization apply to blinded assets; before it, PAK enforcement was skipped outright whenever a peg-out's asset commitment was confidential. That is a real hole and it was real for years. It is not this one: I checked ce4caece… and its peg-out output carries an explicit asset and an explicit value, so PAK ran normally. The lie is in the mint, not in the authorization. And note what the attacker said at 03:30 this morning, ten hours after that patch landed: the chain is under risk at latest commit right now. ━━━━━━━━━━━━━━━━━━━━━━━━ VERIFY IT YOURSELF curl -s blockstream.com/pgp.txt | gpg --import # pull the OP_RETURN from block 965875, strip to the armor, then: gpg --verify yes.asc curl -s liquid.network/api/tx/c652a1…\ 42fa552b0856ba674/status curl -s liquid.network/api/block-hei… ADDRESSES federation bc1qdlld6antmv4xug242ed83q7k4rqw50cwfns38szx4qu2f4jwaxxsuhwxxr attacker bc1ql4mfu6aundtkksxklfajs2h3t9nzcd6gyqjlte Blockstream bc1qn8mgsmxx42j3fflqfkh0cqhdd6mj4h9q2mfqym Signal spoofer bc1q7le6nr37p892jzlyugr5sl29pfcg27xl77eafu mempool.space/address/bc1ql4… The mechanism and the explorer split were first laid out by defiprime, and the range-proof cache commit is their find. What is added here is the cryptography on the negotiation, the composition of the drain transaction, and the second halt. All times UTC. Reserve, supply and tip figures read at 06:42 UTC, 7 September 2026.
3
1
3
447
NOTIONAL FINANCE β€” $1.73M OpenZeppelin flagged the exact line that drained it. In December 2020. Finding L10. Severity: Low. Never fixed. 2,082 days later it emptied the escrow in 337,254 gas. THE LINE The bug is not in mintfCashPair, which is what the alerts named. It is one cast inside the Escrow's ExchangeRate library, compiled with Solidity 0.6.4 β€” before the compiler checked arithmetic for you: uint128 absBalance = uint128(balance.abs()); balance is an int256. abs(-2^128) = 2^128. uint128(2^128) = 0. Seven lines further down, the same function wraps its result in SafeCast.toUint128. The codebase has eleven correct SafeCast calls in Liquidation.sol alone. Somebody swept this repository for unsafe casts and stopped one line short, twice β€” the identical statement sits in _convertETHTo as well. The OpenZeppelin audit of Notional V1, dated 22 December 2020, is finding L10, "Casting between types without overflow checks." It names the function by name: "Within the functions _convertToETH on line 49 of ExchangeRate.sol and _convertETHTo," the int256 balance input is explicitly cast to a uint128. The recommendation was to use SafeCast. The escrow implementation went live on 7 December 2020 β€” fifteen days before that report was published β€” and the proxy emitted exactly one Upgraded event in the following 2,096 days. The audited line was never touched. THE PROOF, IN ONE CALL Point an archive node at the block of the setup transaction and ask Notional what the attacker's account was worth: cast call 0x0a4721117040abf319b954abf13f654505c34920 \ "freeCollateralView(address)(int256,int256[],int256[])" \ 0xec434a2f9b7b93aad1bed77d6bc512a75ae90d78 \ --block 25900220 fc = 0 balances[1] = -340282366920938463463374607431768211456 That second number is exactly -2^128, denominated in DAI. An account carrying 340 undecillion DAI of debt reads as precisely zero free collateral, so require(fc >= 0) passes. The attacker's own contract asserts it: the constructor reverts unless free collateral comes back as 0. WHY TWO CALLS, AND WHY EXACTLY 2^128 ERC1155Trade.safeTransferFrom carries require(value <= MAX_UINT_128), so a single position can never reach 2^128 β€” it stops one short, at 2^128-1, and one short does not wrap. The DAI cash group has numMaturities = 2. Exactly two slots in the cash ladder, and the free-collateral routine sums them before converting to ETH. He filled both: notional 1 at the near maturity, notional 2^128-1 at the far one. 1 + (2^128-1) = 2^128. That single unit of fCash β€” worth one billionth of a DAI β€” is the entire exploit. Without it the sum is 2^128-1 and nothing truncates. The mirror leg is why the trade is profitable rather than merely broken. The counterparty account received +2^128-1 of the same fCash. Positive balances get haircut before valuation, and the haircut lands it at 0xe07024b1071fe9632caee3275fa315e6 β€” 0.8767 x 2^128. Just *under* the wrap point, so it survives intact and reads as +1.9e35 wei of collateral. The debt lands exactly *on* the wrap point and disappears. One number gets erased. Its mirror does not. That asymmetry is the whole $1.73M. A WINDOW THAT OPENS ONCE A QUARTER The near maturity is 1,788,480,000 β€” exactly 00:00:00 UTC on 4 September 2026, and exactly 230 quarterly periods of 7,776,000 seconds. The setup transaction confirmed at 23:58:47 UTC. Seventy-three seconds before it. mintfCashPair requires blockTime < maturity, so the position has to be minted before the boundary. Withdrawing requires the fCash to have matured, so settleMaturedAssets can turn it into a cash balance. Those two conditions cannot hold in the same block. This attack is structurally two transactions straddling a maturity boundary, and that boundary opens once every ninety days. Which is also why the transaction every alert linked β€” the one at 23:58:47 β€” is not the one where the money moved. THE MONEY 21:41:35 1.18197 ETH arrives from an unlabelled service wallet 23:58:47 setup: contract deployed, -2^128 liability minted 00:01:35 drain: 69,257.37 DAI + 1,658,524.86 USDC β€” 100% of the escrow 00:03:35 proceeds forwarded to a second address 00:29:35 689.2 ETH fully inside Tornado Cash Twenty-eight minutes from drain to laundered. The forwarding address is an EOA running an EIP-7702 delegation to MetaMask's EIP7702StatelessDeleGator, batching swaps through LI.FI via ERC-7821 execute() β€” four of his six swap attempts reverted before two landed. The stablecoins cleared at $2,510.67 and $2,514.99 per ETH. Tornado took the proceeds in 25 deposits: six of 100 ETH, eight of 10, nine of 1, two of 0.1. 689.2 exactly. The funding wallet is not labelled anywhere, but its shape is unambiguous: 1,000 transactions in a single day, 419 distinct outbound counterparties against 289 distinct inbound, 99.1% of its ETH amounts non-round, every token movement a bare transfer(). A swap-service payout wallet. It was itself seeded on 6 November 2024 from Binance 18, and has never touched Tornado Cash in its entire history. THE RESPONSE NOBODY REPORTED Notional's account has not posted since 8 April. Every outlet covering this wrote that the team had said nothing. They said nothing. They did something. At 03:35:47 UTC an EmptyProxy stub was deployed. At 04:04:47 the Notional V1 multisig β€” the same Safe that deployed these contracts in 2020, dormant since 21 March 2025 β€” executed a transaction to itself carrying zero value and zero calldata. Eighty-four seconds later, at 04:06:11, it pushed the escrow proxy onto the stub. Four hours, four minutes and thirty-six seconds after the drain. Three hours and thirty-seven minutes after the last Tornado deposit cleared. Between those two events, at 01:09:11, somebody else flash-loaned 15,000 USDC from Morpho Blue, deployed a single-use contract and settled fourteen separate accounts against the now-dead market, pulling 5.67 WETH back out of the escrow. WHAT IS STILL IN THERE 14,211.894948 USDC 18.216201470486059607 WETH 0.00499717 WBTC 0 ETH Not stranded. The stub is not actually empty β€” it keeps an owner-gated transferTo(token, to, amount), and owner() resolved through the proxy returns that same multisig. The team can sweep it whenever they choose. Every user-facing withdrawal path in Notional V1, however, is now gone. And the escrow was not an abandoned husk. A real depositor put in 1,173 DAI and 952 USDC and took out WETH on 15 July 2026. Another withdrew USDC on 27 August, eight days before the drain. ADDRESSES Attacker EOA 0xdacc235a494750193695a111d715c2ca12b5ce38 Exploit contract 0xec434a2f9b7b93aad1bed77d6bc512a75ae90d78 Forwarding EOA 0x8aaf01b6f9acc973274b8718be4d1c1be10e3be6 Tornado funnel 0xc95496c917a41a394efdac3e0882f5903d24de69 Notional Escrow 0x9abd0b8868546105f6f48298eadc1d9c82f7f683 Vulnerable impl 0x8a134e651432a902041643668940c9a9cd270633 Portfolios 0x0a4721117040abf319b954abf13f654505c34920 V1 multisig 0x22341fb5d92d3d801144aa5a925f401a91418a05 Drain transaction: etherscan.io/tx/0xc3f3e318f7… Low severity findings are still findings. This one waited 2,082 days.
1
2
703
AQUIFER β€” SOLANA, 31 AUG 2026 Coverage says Aquifer's contracts were not exploited and points at wallet compromise. All 212 drain calls invoked a program the attacker deployed 5m31s earlier. Aquifer never checks the program it calls. solscan.io/tx/59FaTv9PG7rbaf… THE BUG Aquifer's swap instruction takes the SPL token program for each leg out of the caller's account list and CPIs it without checking that it is the token program. Proof, one instruction, 04:04:18 UTC: top level AQU1FR... data 01 920dd28f2a000000 discriminator 1, amount_in 182,801.534354 USD1 CPI 1 spl-token transfer 182,725.676811 USDC from vault 7ULN1YSsJ3tnC98PVko7qTS5iGzX73QY74vgMeHjwvkW authority GtwzYxBQcPFNFQcYbdELuaKzb4DGJpGVU2ehLhzbffCw (Aquifer PDA) to the attacker's ATA CPI 2 DMBpPMaMpGM2mWiUMaqcHx9FwhPg9Ys7qg1X59NRgb68 data 03 920dd28f2a000000 byte-for-byte an SPL Token "Transfer" for the same amount 858 compute units, no state change DMBpP... is not the token program. It is a 20,424-byte program the attacker deployed himself at 03:35:56 UTC, upgrade authority = his own wallet. The "source" account it was handed, Fd3ug1B14aedt6NGpiC55mXgHT3L9cspYBitcooAy6EV, is 165 bytes β€” SPL token-account layout β€” owned by DMBpP... rather than by the token program. The pool paid out real USDC and received nothing. Not a key compromise. A missing owner check on a program account. 212 of 212 successful calls have exactly this shape: Aquifer discriminator 1, two CPIs, one real transfer out (195x spl-token, 17x Token-2022) and one call into DMBpP... for the paying leg. No exceptions. THE PREPARATION 01:21:22 wallet funded with 2.3649 SOL from an instant-exchanger hot wallet, memo "087b7ae2" 03:35:06 20,461-byte buffer created, 24 write chunks 03:35:56 DMBpP... deployed 03:36:01 45 transactions, one per mint: a fake 165-byte "token account" owned to by DMBpP..., for 45 different assets. All 18 pools he later drained 03:37:44 are in that list β€” the target set was chosen before the first call. 03:41:27 first exploit call Five minutes thirty-one seconds from deploy to first drain. THE 40 MINUTES 03:41:27 first call: $4,931 (195,849 KMNO) 04:04:00 22m33s and 26 calls in β€” $75,728 taken, 3.1% of the eventual loss 04:08:25 25% mark 04:09:43 75% mark β€” half the entire loss moved in 78 seconds 04:21:19 last call 212 calls, 18 pools, $2,444,568 priced at 04:20 UTC. DeFiLlama's registry says $2,469,729 β€” a 1% gap, from two different price sources rather than two different reconstructions. THE ACCOUNTING All 18 drained vaults together hold $69.69 today. Not a partial drain β€” every pool went to zero. The SOL side closes too: 24,085.17 SOL in from the swaps, 24,085.02 out, 0.15 left behind. THE OFFER IS REAL Worth stating, because a fake whitehat offer is the standard follow-up to a public one. This one checks out. The memo transaction u1hoSUTz... (16:43:27 UTC) executed through Squads v4, logging "Signed by 8pJhHxPQRiUGdtVSCNPyP9AH994zeyYEBGb5yZRzheSA", with a 1-lamport transfer from that same account to the attacker. Reading the program directly: getAccountInfo AQU1FRd7pap... -> programData GrHYWjuGETV5pZgUZLfzvvQEugYk6SutwHUPxFjrHda6 getAccountInfo GrHYWjuGETV5... -> authority 8pJhHxPQRiUGdtVSCNPyP9AH994zeyYEBGb5yZRzheSA Same key. The offer really is from the holder of the upgrade authority. The Ethereum mirror landed at 16:50:47 UTC from 0x09dA08045830492B24b3b8A0022375e662bbE91d. THE ANSWER 24,084.479 SOL left Solana in three legs through Rango, the route ending in Circle CCTP v2, and came back as 1,000.7955471888082 ETH β€” 871.860 + 122.509 + 6.426 β€” with 45 to 60 seconds of solver latency per leg. Then it sat for 27 hours 54 minutes. On 1 September at 20:37:23 UTC the whole stack moved in a single transaction to 0x200e52350fbc579c96bad87b6ef782c1f962dffd β€” a fresh vanity EOA with no prior history, no outgoing transaction, and a balance today of exactly 1,000.7955471888082 ETH. That is 41 hours 23 minutes before the 3 September 14:00 UTC deadline, and it is the answer to the offer. Nothing reached either recovery address: the Solana one has held 0.98 SOL and been silent since 9 February; the Ethereum one has not moved. THE POISONERS Twelve seconds after that transfer a fleet started mirroring the payee. Fake ERC-20 contracts named "ETH", "Eί H" and "Ether.." emitted transfers of exactly 1,000.7955471888083 from the attacker to 0x200aceda1b..., 0x200ef02e9c..., 0x2000d091d2... and 0x200e3afa6b... β€” and one to the real 0x200e52350f..., so the lookalikes sit in the history beside a genuine entry. Then 1-gwei dusts from the same set. Every address is 200...dffd. They copy the payee, not the victim. The same thing happened on Solana: 7fTeniVLMFsaP5EXC4e2yZL62msxh4yTGyiChVUEERNJ β€” same four-character prefix as the attacker's 7fTe9pvr... β€” dusted the Rango escrow at 04:28:00, six minutes after the last leg passed through it. And on 1 September at 10:59 someone wrote to the attacker from 0x378ce730a46c04b28168f3e4bf78af23b317de79 asking him for 10 ETH. STILL THE SAME BUILD The Aquifer program has not been upgraded since 11 August 2026, 11:51:44 UTC β€” programData last_deploy_slot 438601204, and nothing after it in the loader's history. The vaults are empty, so there is nothing left to take; the point is that the build on chain is the one that was drained. ADDRESSES attacker (SOL) 7fTe9pvrwXJRBHq9MaSyVPR4PgEuhqLiA93Dxf4gRk7J attacker (ETH) 0x2Dfe9e969796e2797278b02761dd9Ad6aE922746 attacker program DMBpPMaMpGM2mWiUMaqcHx9FwhPg9Ys7qg1X59NRgb68 fake token acct Fd3ug1B14aedt6NGpiC55mXgHT3L9cspYBitcooAy6EV Aquifer program AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45 upgrade authority 8pJhHxPQRiUGdtVSCNPyP9AH994zeyYEBGb5yZRzheSA 1,000.79 ETH now 0x200e52350fbc579c96bad87b6ef782c1f962dffd The incident and the two attacker addresses were first published by Defimon and covered by crypto.news on 1 September. The mechanism above is ours.
1
374
CertiK and PeckShield put the Tectonic hack at $74-75M. That's only the stablecoins sent to one address. Tectonic's own market balances fell $119.1M. $42.4M of it sits in a contract nobody has named: 0x085f3115ca368aa262246d22f9476e1e2c87e8be I reconstructed the whole thing from Cronos archive state, because the public explorer is down and the chain is still halted. ── THE ADDRESSES NOBODY NAMED ── Attacker EOA: 0x4266a0e6a0f0ef90abcff3bb089932ca0cce3652 Orchestrator contract: 0xd3aac8a1a9e412e2c590463a8b6f90125e23f1f3 (deployed Aug 30, 12:38:56 UTC) Borrower contract: 0x2dc6a36f4e5eeefe112c01569de96dea496bb618 (created in the same tx) Vault contract: 0x085f3115ca368aa262246d22f9476e1e2c87e8be β€” deployed by the same EOA on Aug 18, 14:47:15 UTC. Twelve days before the exploit. It currently holds 13,978,766 USDC, 9,812,697 USDT, 92.04 WBTC, 1,765.10 WETH, 32.93 CDCBTC, 349.67 CDCETH, 23,093,728 LCRO, 24,287,549 WCRO and 120,650 XRP. About $42.4M. Starting capital: 5,000,950 USDC, bridged onto Cronos in $100-500K tranches between Aug 28 and Aug 30 through 0xcdfba496180865a71266608ade6b21ab1f788888. ── WHY $74M IS THE WRONG NUMBER ── The drain transaction is 0xddc9dc47d330116332ae687ba939f6d6196c4cc5950b2cdb04ae826520eeca20 One call. Selector 0x26faf313 β€” borrowMax(). It borrowed the entire cash of every market, matching each market's cashPrior to the unit: USDT 34,238,092.49 β†’ 0x7d4e $34,235,145 USDT 11,412,697.50 β†’ 0x085f $11,411,715 USDC 41,429,611.35 β†’ 0x7d4e $41,427,963 USDC 13,809,870.45 β†’ 0x085f $13,809,321 WBTC 98.04 β†’ 0x085f $7,713,270 WETH 1,895.10 β†’ 0x085f $4,669,805 CDCBTC 32.93 β†’ 0x085f $2,590,723 LCRO 26,243,727.70 β†’ 0x085f $2,104,797 CDCETH 379.67 β†’ 0x085f $1,005,170 WCRO 16,745,476.51 β†’ 0x085f $1,028,641 XRP 270,650.42 β†’ 0x085f $378,736 ─────────── $120,375,285 Stablecoins were split exactly 75/25 between 0x7d4e and the unnamed contract. Everything else went to the unnamed contract at 100%. 41,429,611 + 34,238,092 = $75.66M. That is the "$75M at three addresses." Both firms counted the 75% slice of two assets and stopped. Tectonic's market cash, before the attack vs. at the halt, priced with the protocol's own oracle from before the manipulation: tUSDC 54,325,388.59 β†’ 0.03 -$54,320,567 tUSDT 45,550,247.50 β†’ 966,882.66 -$44,579,503 tWBTC 98.18 β†’ 4.45 -$7,361,887 tWETH 1,885.07 β†’ 34.28 -$4,564,140 tCDCBTC 33.30 β†’ 0.13 -$2,605,552 tCRO 46,053,295.86 β†’ 1,977,118.96 -$2,536,848 tLCRO 26,880,464.61 β†’ 3,147,757.71 -$1,783,431 tCDCETH 380.79 β†’ 0.65 -$1,007,191 tXRP 270,650.42 β†’ 8,213.53 -$366,692 ──────────── -$119,125,811 tUSDC has three cents left in it. ── IT WAS NOT AN ORACLE TRICK IN ONE BLOCK ── Setup tx: 0x0fce5ae8d2eeb82c838e750d0e25af1564a2c7d05bf843dd1cfea102ce587d06 β€” 33.2M gas, 677 logs. 1. Deposit 5M USDC as tUSDC. CF 0.8 β†’ ~$4M of borrowing power. 2. Borrow the entire tTONIC market: 3,844,366,314,940.79 TONIC, worth ~$4.08M at the real price of $1.0622e-8. Right at the limit. Nothing broken yet. 3. Re-deposit that TONIC through the second contract. 4. Repeat. And after 12 loops the mint stops being necessary β€” the borrower simply sends TONIC to the tTONIC contract as a plain ERC-20 transfer. Cash refilled, no accounting event, borrow again. 98 iterations. End state of one transaction: β€” parent debt: 376.5 trillion TONIC β€” child collateral: 309.2T tTONIC = 335.7 trillion TONIC TONIC's total supply is 500 trillion. The attacker's collateral claim was 67% of every TONIC in existence, and 14.7x all the TONIC sitting in every DEX pool combined. Those pools held about $0.5M across both sides. tTONIC's totalSupply went from 60.06T to 369.26T in that single transaction. One address created six times more deposits than existed before it. ── THE SECOND INFLATION NOBODY MENTIONED ── In Compound v2, exchangeRate = (cash + totalBorrows - reserves) / totalSupply. Outstanding borrows count as assets of the market. So the attacker's own unbacked 376.5T TONIC debt landed in the numerator of the token he was posting as collateral. tTONIC's exchange rate went 1.354e9 β†’ 1.0857e10 in that one transaction. An 8x jump. Roughly 95% of the tTONIC market's balance sheet was the attacker's own debt. ── THEN THEY JUST WAITED FOR THE FEED ── Three follow-up transactions (12:40:39, 12:41:29, 12:45:25, selector 0x7b9f30b8) each borrowed USDC and CRO against the inflated collateral, bought TONIC on VVS with it, and donated the TONIC back to the tToken contract. Total fed into the pools: 3,509,440 USDC + 28,163,915 CRO β‰ˆ $5.24M β€” all borrowed from Tectonic itself. The first attempt at 12:40:39 reverted; they adjusted parameters and retried. TONIC's price in Tectonic's oracle (0xd360d8cabc1b2e56ecf348bff00d2bd9f658754a), block by block: $1.0622e-8 baseline $6.8593e-8 after the setup tx $9.1889e-7 around block 90,896,600 $2.0763e-6 around block 90,897,080 ──────────────────────────────── x195.5 in about four minutes The price is flat between updates and then jumps. This is a pushed feed that follows the manipulated DEX price with a lag. The attacker never had to beat an oracle inside a block β€” he bought TONIC and waited for the feed to catch up. Collateral value of the borrower contract as it moved: 12:38:56 $3,565,813 12:40:39 $23,026,727 12:45:25 $314,381,596 12:49:39 $710,376,013 At a 0.2 collateral factor, $710M of collateral is $142M of borrowing power. They took $120M and left. ── WHERE THE MONEY IS ── At block 90,907,150, the moment Cronos stopped: 0x7d4e...f2dc β€” $60,115,712 0x085f3115... β€” ~$42,410,000 0x215adfc8... β€” $7,770,094 USDC Ethereum 0xc404160b... β€” 2,592.215 ETH β‰ˆ $6,390,000 ───────────── β‰ˆ $116.7M One correction to every tracker showing 0x7d4e: a token scan shows it empty. The $60.1M is a 75.008% LP position in the VVS USDT/USDC pool 0x39cc0e14795a8e6e9d02a21091b81fe0d61d82f9. Thirty million USDC and thirty million USDT went in, LP tokens came back. ── THE HALT DIDN'T CATCH THE ETHEREUM LEG ── Between 13:03:23 and 14:15:47 UTC, 6,336,359.647494 USDC moved to 0xc404160b79bd8905061a1caecbeca2eeab3f72dd on Ethereum in 34 tranches, relayed by 0xf70da97812cb96acdf810712aa562db8dfa3dbef β€” an intent-bridge solver that also appears on the Cronos side, not the canonical bridge. Every cent was swapped into ETH through the Uniswap v3 USDC/WETH 0.05% pool. 2,563.22 ETH received, average $2,472.02. Cronos halted at 14:32:47 UTC β€” 1 hour 43 minutes after the drain. That address was still swapping at 01:43 UTC the next day. Balance now 2,592.215 ETH. ── A WARNING ON THE ADDRESSES IN THOSE ALERTS ── Minutes after the drain, address-poisoning bots mirrored the transfers with counterfeit USDC and USDT (0xa9f071191cc59b4a0a970dca02a16ddfe803719b, 0xc6203d86f5efbed7f9512755f3e6132ee50d03d1) sent to lookalikes: 0x7d4eb7d6fd2bd97ffa042fe8814accf12674f2dc 0x215ab1ddc9d7b079202371ef5332d37dcfdcd3fc 0xc404df04ce19dbbdd0350e2ea4e7b3eff4ff72dd PeckShield's abbreviation "0xc404...72dd" matches both the real address and the poisoned twin. The real one is 0xc404160b79bd8905061a1caecbeca2eeab3f72dd. CertiK's alert lists three links, but 0x7d4e...f2dc appears twice β€” the third address was never actually named. ── STATUS ── Cronos has produced no blocks since 14:32:47 UTC on Aug 30. Two independent RPCs agree on the same head, block 90,907,150. That is more than eleven hours. explorer.cronos.org is also down β€” its backend returns an internal server error on every address, so Tectonic's verified sources are unreadable right now. Everything above was rebuilt from events and archive eth_call, not from source. Against the ~$119.1M hole, the protocol holds the attacker's 5M USDC and 335.7T TONIC of collateral, now worth about $9.8M after the price fell back to $3.0067e-8. Net bad debt is on the order of $105-110M. All USD figures use Tectonic's own oracle at the block before the attack, to keep the manipulated spot out of the arithmetic.
4
5
2
30
4,413
Ajna V2 is still being drained. Coverage says ~$775K across 7 pools, one attacker, past tense. The chain says 13 pools and 6 separate addresses running 6 different exploit contracts β€” and the newest auction was kicked 10:37 UTC today. etherscan.io/tx/0xa199d8edd9… THE FINGERPRINT β€” one transaction, every time: addQuoteToken into a bucket far above the pool's top-of-book β†’ drawDebt twice against that self-made price β†’ kick both of your own loans. Wait out the 1-hour take cooldown. Then bucketTake your own bucket from the other auction. Every one of the 13 deposits lands above the incumbent top bucket: cbETH/WETH index 2000 vs 4151 Β· sUSDe/DAI 1000 vs 4157 Β· wstETH/WETH 1 vs 4129 THE DEFECT β€” Ajna already shipped the check that stops this: Pool.removeQuoteToken calls _revertIfAuctionDebtLocked. Deposit backing live auction debt is frozen. TakerActions._takeBucket reaches the same deposit tree at a caller-chosen index and never calls it. At the cbETH take block the frozen band covered the attacker's own bucket: debtInAuction 98.724790 > depositSize 98.687750 β†’ findIndexOfSum returns 7388 β†’ 2000 <= 7388 reverts. depositIndex(1) = 2000. Their bucket was top of book, squarely inside the band the code's own comment calls frozen. The guard exists. It sits on the other function. DRAINED β€” quote token, pre-attack vs now: sUSDe/DAI 163,371 DAI 99.3% syrupUSDC/USDC 89,921 USDC 97.4% cbETH/WETH 48.88 WETH 99.1% wstETH/WETH 48.62 WETH 95.5% mwstETH-WPUNKS 35.71 wstETH 92.9% WBTC/DAI 28,472 DAI 81.7% WETH/USDC 25,500 USDC 88.6% sDAI/USDC 14,244 USDC 97.6% sDAI/USDC 11,835 USDC 89.5% + 4 smaller pools sUSDe/DAI is the second-largest loss in the campaign and appears in no published breakdown. SIX ACTORS, NOT ONE: 0x6f2f5236 Aug 28 15:18 first mover β€” 7x1 ETH from Tornado, purpose-built 24,328-byte contract, 1 pool 0xcccc6400 Aug 28 18:27 4 pools 0xc213145e Aug 28 22:12 4 pools 0xb929c721 Aug 28 23:30 1 pool 0x3c443553 Aug 29 00:34 1 pool 0x73433e6b Aug 29 19:12 2 pools, latest today Six exploit contracts, six different bytecode sizes, six different hashes β€” 24,328 / 11,280 / 8,484 / 12,024 / 12,264 / 11,863 bytes. Five of the six EOAs have long prior histories; only the first is freshly funded from a mixer. That is not one fleet. It reads as the first exploit being reverse-engineered inside three hours and re-run against every remaining pool β€” and still running 30 hours after the team asked users to withdraw. Mechanism first named publicly in the DeFiHackLabs PoC. Defimon says it flagged the prepared attack over an hour before the first transaction landed.
320
🚨 Term Finance β€” $8.53M governance attack The veto that was meant to stop it cost $951 to buy. Voting power comes only from staked vault shares. 0.5352 of 2,838.95 were staked β€” 0.019%. The attacker held 90.66% of it. Term's Strategy Vaults were sold on exactly this safeguard: "LP token holders retain veto power over risk parameter adjustments." The attacker did not beat the veto. He bought it. How it worked Voting rights on the ETH Meta Vault don't come from holding tmvETH. They come from staking it into the Governance ETH Meta Vault. On the block before the drain, the entire staked supply was 0.5352 gtmvETH against 2,838.95 tmvETH outstanding β€” 0.019% of the vault. Aug 17, 05:19:11 UTC: the attacker deploys a contract at his own nonce 0. It is named "Fixed Recipient WETH Exit Strategy", ticker frWETH-EXIT. 05:21:47: he buys 0.4852 tmvETH for 0.5 ETH (~$951 at that hour's price) and stakes it. That is 90.66% of every vote in existence. 05:25:35: he opens the veto proposal β€” carrying Term's own boilerplate: "Vote YES to VETO the curator's proposed vault parameter changes. Otherwise, the transaction will become executable when this proposal expires." Nobody voted. It expired Aug 23, 06:25:35. It executed at 06:25:47 β€” 12 seconds, one block, after the window closed. The holder who could have stopped it One EOA held 2,837.28 tmvETH β€” 99.94% of the vault. Unstaked, so zero votes for all 145 hours. They staked it at 07:59:23 today. 94 minutes after the money was gone. The books still show the money The vault handed over 2,841.7435 WETH and received 2,841.7435 units of the attacker's own contract, which its accounting values 1:1. totalAssets() before the drain block: 2,926.2159 ETH totalAssets() after the drain block: 2,926.2159 ETH WETH balance: 0 Share price: still 1.0308 ETH maxDeposit: 47,073 ETH β€” deposits open (checked 09:45 UTC) maxWithdraw: 0 The USDC leg is five more vaults One transaction, 06:47:47, took 1,679,639.29 USDC: Parity High Yield USDC v2 β€” 848,410.95 RockawayX Tori USDC β€” 454,046.26 Parity High Yield USDC β€” 348,877.20 Parity Core USDC β€” 14,172.39 Parity Prime USDC β€” 14,132.49 Converted to 1,679,642.45 DAI. Every one of the five reports the same or a higher totalAssets after the drain than before β€” they are still accruing yield on assets that left. Across all six victim vaults the books publish $11.41M. $8.53M of it does not exist. Two more captures are loaded and unfired Eight takeovers were queued. Six went off. Two never did: Parity Core ETH β€” veto window expired today 06:30:47 Parity Prime ETH β€” veto window expired today 06:36:47 Those two vaults hold 8.99 + 75.63 = 84.62 ETH (~$204K) β€” which is precisely the residual the emptied ETH Meta Vault still claims to own. The last of it sits behind two locks that were already picked. Windows don't reopen. Funding Tornado Cash 1 ETH pool, twice: 0.9945 ETH on Aug 17 05:01:11 and 0.9944 ETH on Aug 18 03:59:59. Both execution transactions carried a priority fee of exactly 0 β€” nothing ever hit the public mempool. ETH drain: etherscan.io/tx/0xd354a15b15… The $8.5M figure and the addresses were first published by CertiK Insight and @osint_based. The cost of the veto, the empty books and the two live windows are ours. Addresses Attacker 1: 0xa908b3472d76e7744baB0A5911768a4a6300612B Attacker 2: 0x686457a7468B9B31c5dbA43b1b16077B48520691 Funds: 0xD5183d8BfC65a50863C62aF2538198A8288FFc13 Fake strategy: 0x184f2e57b4ce135181fa2a2166ac394339016338 ETH Meta Vault: 0x26fcb50eec367ddab060ccf5e7394cecd95f7db2 Governance ETH Meta Vault: 0x5b96c5bbdcb361e1e9944baa071b237e27829be0
1
1
5
1,459
Update, six days on. Two things in the post above have changed, and one of them is the vault agreeing with us. totalAssets() no longer reads 2,926.2159 ETH. It reads 84.4709 ETH. Deposits are closed and the share price is 0.029756, down from 1.030752. The figure we derived on day one from a zero WETH balance was 84.47. The writedown landed 0.0014 ETH away from it. Also: 300 ETH went through Tornado Cash on Aug 24, and Term opened an on-chain comms channel on Aug 27. Full follow-up: teapawt.org/BlockWatchdog/status/2…
🚨 Term Finance, day 6: 300 ETH went through Tornado Cash on Aug 24. Term's first on-chain word to the attacker came on Aug 27 β€” three days and $742K later. The vault has since written down 97.11% of itself. The money moved first Aug 24, 17:27:47 β€” 100 ETH leaves the consolidation address for a fresh EOA, 0xc1400766…d83e 17:29:59 β€” a 0.05 ETH test 17:30:23 β€” 100 ETH into the Tornado Cash router 17:31:47 β†’ 17:31:59 β€” another 100 ETH, same path 20:52:47 β†’ 20:53:11 β€” a third 300 ETH, ~$742K at that afternoon's price. The hop wallet is now down to 0.035 ETH. Then Term spoke Aug 27, 17:28:23 β€” a Safe writes to the attacker in calldata: "this is termfinance.eth. please use 0x78cC562D740f44CCA18AA74126C6dD23F8cFcD38 for comms on blockscan going forward" We checked it three ways before repeating that address, because the last protocol we watched do this got impersonated within hours: termfinance.eth resolves to 0x0842fdfb… β€” the exact Safe that sent it. The signer 0x1b84ddff… is one of that Safe's three owners. The nominated comms address was first funded on 24 July 2024 by 0x7142b642…, another owner of the same Safe. Two years old, not minted for the occasion. All three hold. This is Term. But it is only a handshake β€” the follow-up from the comms address says nothing except "please read" and links back to the Safe message. No terms have been offered yet. The writedown On day one we put the real residual of the ETH Meta Vault at 84.47 ETH, derived from a WETH balance of zero against a book that still read 2,926.2159. Today the vault's own totalAssets() reads 84.4709 ETH. Share price has gone from 1.030752 to 0.029756 β€” a 97.11% writedown. maxDeposit is now 0. The attacker's contract is still sitting inside the vault: 2,841.7435 frWETH-EXIT, exactly as deposited. It is simply worth nothing now, which is what it always was. What is still out there At the consolidation address: 2,543.15 ETH + 1,679,642.45 DAI (~$7.89M). And the two takeovers that were queued and never fired still have their targets intact β€” Parity Core ETH holds 10.44 ETH, Parity Prime ETH 75.94 ETH. Whether those transactions remain executable is something only Term can answer. Addresses Funds: 0xD5183d8BfC65a50863C62aF2538198A8288FFc13 Tornado hop: 0xc14007663a5bb9f13d4d2aee8c6fe9075ef1d83e Term Safe (termfinance.eth): 0x0842fdfb5940ef6a4ea6c5dee024eec1ddc6977d Term comms: 0x78cC562D740f44CCA18AA74126C6dD23F8cFcD38
1
71
🚨 Term Finance, day 6: 300 ETH went through Tornado Cash on Aug 24. Term's first on-chain word to the attacker came on Aug 27 β€” three days and $742K later. The vault has since written down 97.11% of itself. The money moved first Aug 24, 17:27:47 β€” 100 ETH leaves the consolidation address for a fresh EOA, 0xc1400766…d83e 17:29:59 β€” a 0.05 ETH test 17:30:23 β€” 100 ETH into the Tornado Cash router 17:31:47 β†’ 17:31:59 β€” another 100 ETH, same path 20:52:47 β†’ 20:53:11 β€” a third 300 ETH, ~$742K at that afternoon's price. The hop wallet is now down to 0.035 ETH. Then Term spoke Aug 27, 17:28:23 β€” a Safe writes to the attacker in calldata: "this is termfinance.eth. please use 0x78cC562D740f44CCA18AA74126C6dD23F8cFcD38 for comms on blockscan going forward" We checked it three ways before repeating that address, because the last protocol we watched do this got impersonated within hours: termfinance.eth resolves to 0x0842fdfb… β€” the exact Safe that sent it. The signer 0x1b84ddff… is one of that Safe's three owners. The nominated comms address was first funded on 24 July 2024 by 0x7142b642…, another owner of the same Safe. Two years old, not minted for the occasion. All three hold. This is Term. But it is only a handshake β€” the follow-up from the comms address says nothing except "please read" and links back to the Safe message. No terms have been offered yet. The writedown On day one we put the real residual of the ETH Meta Vault at 84.47 ETH, derived from a WETH balance of zero against a book that still read 2,926.2159. Today the vault's own totalAssets() reads 84.4709 ETH. Share price has gone from 1.030752 to 0.029756 β€” a 97.11% writedown. maxDeposit is now 0. The attacker's contract is still sitting inside the vault: 2,841.7435 frWETH-EXIT, exactly as deposited. It is simply worth nothing now, which is what it always was. What is still out there At the consolidation address: 2,543.15 ETH + 1,679,642.45 DAI (~$7.89M). And the two takeovers that were queued and never fired still have their targets intact β€” Parity Core ETH holds 10.44 ETH, Parity Prime ETH 75.94 ETH. Whether those transactions remain executable is something only Term can answer. Addresses Funds: 0xD5183d8BfC65a50863C62aF2538198A8288FFc13 Tornado hop: 0xc14007663a5bb9f13d4d2aee8c6fe9075ef1d83e Term Safe (termfinance.eth): 0x0842fdfb5940ef6a4ea6c5dee024eec1ddc6977d Term comms: 0x78cC562D740f44CCA18AA74126C6dD23F8cFcD38
290
Avici drain: no admin key was stolen. The attacker put two Ed25519 instructions in one tx. The second declared the victim's admin, but its offsets pointed back at the first. Solana's precompile verified his own throwaway key twice. solscan.io/tx/2j5y2oK3mUhUUk… CertiK Alert and the STACC tracker gave the sequence β€” SubmitSignatures, AddCollateralAdmin, WithdrawCollateralAsset. Nobody has said why the first step worked. Here is the answer, from the bytes. HOW THE SIGNATURE WAS FORGED Solana's Ed25519 precompile takes offsets, not values β€” including which instruction to read the signature, key and message from. 0xFFFF means "this one". Anything else is an index into the transaction. ix #0 β€” key 5pnmMmrYvV5AqA7Pbg78pg9Z3b44Z6btuPXRzascBuUJ, a real signature over digest 3987cb1b…00b55fbd. Valid. That key has zero transactions on Solana: generated for this. ix #1 β€” signature, pubkey and message instruction indexes all set to 0. The precompile walks back into ix #0 and verifies the same signature a second time. Inside ix #1's own bytes sits BSXShSaFBYehwScTNL4dw5NAk1XuygfittdGGHTKyiiu, an admin of that collateral, and 64 bytes of 0x09 where the signature should be. Nothing ever reads them. The program parses each Ed25519 block as self-contained β€” programs/main/src/signature/utils/get_ed25519_signatures.rs, the path survives in the compiled binary β€” counts two distinct admin signers, and accepts. AddCollateralAdmin then writes the attacker into the collateral's admin list. After that he signs for real. One forgery per account. Both signatures checked locally against an independent Ed25519 implementation: ix #0 valid, ix #1 not a signature for anything. WHOSE CODE THIS IS The drained program ships its own security.txt: name Collateral Program version 2.05 project_url rain.xyz/ auditors Sherlock The same binary carries EIP-712 typehashes β€” AddAdmin(address admin,uint256 nonce), Withdraw(address user,address asset,uint256 amount,address recipient,uint256 nonce). This is a port of an EVM contract. ecrecover takes no offsets; the bug cannot exist there. Sherlock's public Rain audit is dated 3 Jan 2023 and covers the Solidity side. The bug class was published on 22 Sep 2025 β€” Asymmetric Research, "Wrong Offset: Bypassing Signature Verification in Relay" β€” naming the exact Ed25519SignatureOffsets fields that must be validated. First drained deployment shipped 13 Oct 2025. Second, 20 Nov 2025. Neither was upgraded until the day of the incident. FOUR PROGRAMS, NOT TWO CWgkFB7ngUc9cGD1LryyhP7h6xYWtwrAjhSKKCoR1gkz 16:49:49–18:37:05 626,221.81 USDC 3zVB27Gap6fbxpAcV2hsBBUcV3vRjkCikBXREiyBzDuc 17:02:16–19:18:52 12,128.36 USDC + 44,227.08 USDT 8r2jms1vAnHhtCWxDNSgiHvQNSzzJvGa9oBRCbBPCBNN 18:36:19–18:36:21 64.13 USDC 26DkA98jjctzPkBEteUsN935CR4dsKx3XvjrtE7MeL4a 18:44:36–19:18:49 185,484.27 USDC + 247,852.58 USDT The third one is a two-second probe worth 64 USDC. It matters because it proves the script was walking a list of deployments, not targeting one brand. One upgrade authority β€” EfQ2zvc1xQfscTxCPb1om4s1CetncrfVFSt5zwiUR99J, a plain account, not a multisig β€” pushed new versions into at least 25 distinct program IDs between 19:18 and 21:29 UTC. The largest one the attacker never reached holds 34,476 collateral accounts and was patched at 19:43:14. FIFTEEN SECONDS 19:18:37 first patch lands, on the program the attack started from at 16:49 19:18:52 last successful withdrawal β€” on 3zVB27Ga…, still unpatched 19:43:42 3zVB27Ga… patched, 24m50s after the last theft cleared it The drain did not stop because of the patch. After 19:18:52 there is not one further attempt, successful or rejected. WHAT THE NUMBERS ACTUALLY ARE reported ~$1.02M ~418 ETH 2 programs 125 senders on chain $1,115,978 455.9 ETH 4 programs 2,930 collateral accounts $1,115,978 = 823,898.57 USDC + 292,079.66 USDT across 5,262 WithdrawCollateralAsset calls. 455.9 ETH went into Tornado in 23 deposits between 19:20:11 and 19:49:23. At $2,440.34/ETH that is $1,112,631 β€” the two independent counts close to 0.3%. The 418 ETH everyone quotes is one bridge leg. There was a second: 886.94 SOL swept at 19:26:34, out through deBridge, 37.478 ETH landing on 0xd70d0f832a9163af4aca0b6f7b282bb0b15be75e and forwarded on. Total cost of the attack: 0.26 SOL in fees. Funding was 1.7885 SOL, bridged in three hours before the first forgery. Rain has published no post-mortem. It acquired Guardrail, a runtime-monitoring service advertising response "in under 100 milliseconds". The drain ran 2h29m and 21,405 transactions.
2
1
9
4,215
Everything above is checkable. The rest of the trail: attacker (Solana) FVNFzqAny8spWdPmYw6RQ9TkYa29ueFFiqCFD1gQnCEj laundering (ETH) 0x2cE21E4921d3Eb116526c3651Dac0257657338D5 second bridge leg 0xd70d0f832a9163af4aca0b6f7b282bb0b15be75e funding (ETH) 0xa1a15f1b0d4878873f2933573e4385ab1e4df25c The Solana wallet was never funded from an exchange. Its only inflow is a deBridge payout, and the bridge's own API returns the order's maker on the source chain: 0xa1a15f1b…, an address with exactly two transactions ever β€” 0.0795 ETH in, then a swap to USDC to pay for the order. That ETH came from 0x775028b2ce02844e8947905e4d655940a76cf559 β€” 202 transactions since 20 Aug, ~$680K of USDC/USDT paid out to dozens of addresses. Operational or OTC wallet, not an exchange deposit. I am not claiming it is the attacker. Side note: both the laundering address and its funder were address-poisoned the same evening β€” 1-gwei transfers from 0x2ce2887882… and 0x2ce234335e…, plus a fake token spelled with a Unicode Ề᠋SDC. Somebody tried to rob the robber.
2
284
🚨 Moonwell / Base β€” $9.15M bad debt CertiK named the MAMO price manipulation. That alone bought $3.25M of borrowing power; $11.03M was borrowed. The other 72.8% came in through a plain ERC-20 transfer. The mMAMO market has a supply cap: 20,000,000 MAMO. It worked. 09:13:07 UTC β€” the comptroller rejects a 1,000,000 MAMO mint: "market supply cap reached" 09:19:59 β€” 34,910,396 MAMO transferred straight to the market contract 09:21:07 β€” the comptroller now rejects a mint of 1 wei 09:21:09 β€” 18,482,894 MAMO transferred straight to the market contract basescan.org/tx/0x056597f423… Two logs in that transaction. AccrueInterest, Transfer. No mint, no comptroller call, no cap check, 120,017 gas. Compound-v2 exchange rate is cash Γ· mToken supply. Donating cash re-prices every mToken already outstanding: exchangeRate 0.0205133 β†’ 0.0754604 (3.679x) market cash 18.27M β†’ 71.66M MAMO (3.58x the cap) their collateral 15,089,595 MAMO minted β†’ 55,508,833 MAMO credited THE ARITHMETIC The oracle feed went $0.010482 β†’ $0.431274 (41x) across ~30 multi-pool buys. Two levers, and only one of them was reported: price pump alone, 15.09M minted $3.25M borrowing power price pump + donation $11.97M actually borrowed $11.03M The cap was never the binding constraint. The attack stopped when an AERO borrow was rejected for insufficient liquidity β€” $1,422 of headroom left. THE HOLE Drawn: 71.355 cbBTC Β· 623.60 WETH Β· 2,560,000 USDC Β· 368 wstETH. Ten liquidators recovered ~$1.8M and dumped the seized MAMO; the price is back at $0.0116. Four of those liquidations were executed by Moonwell's own OEV wrapper. Collateral left on the position: 7.08 MAMO. Bad debt at 11:20 UTC: $9,150,274, accruing. $8.7M is what reached Ethereum. It is not what Moonwell lost. For scale: the entire MAMO inventory across the 21 pools the buys routed through was worth ~$920K before any of this. THE MONEY Aug 21–23 11 Tornado Cash withdrawals Aug 24 1,947,391 USDC bridged to Base over CCTP Aug 25 dry run β€” 10,000 USDC into Moonwell and back out, two minutes Aug 26 75,000 USDC β†’ 7,407,608 MAMO at $0.010125, 32h ahead Aug 27 582,000 more MAMO borrowed from mMAMO itself 09:41–42 8,729,453 USDC burned to CCTP 09:44:47 8,728,318.997 USDC β†’ DAI in the Maker PSM, 84 seconds after landing 09:45:47 forwarded. Still sitting there, untouched. The USDC was never still long enough to be frozen. RESPONSE 10:53:43 UTC β€” borrow caps set to 1 wei across all 21 markets. 83 minutes after the last borrow, 71 minutes after the funds left the chain. 11:09:43 UTC β€” mMAMO supply cap set to 1 wei. Collateral factor untouched at 0.5. Mint and borrow guardians never paused. ADDRESSES Operator 0x719eae70d4A83f35bF82A2740699F5db84BE919D (Base) Treasury 0xD71dD9B6e634412713c47fe7aE02c628e338C384 (Base + Ethereum) mMAMO 0x2F90Bb22eB3979f5FfAd31EA6C3F0792ca66dA32 mcbBTC 0xf877ACAFa28c19b96727966690b2f44d35ad5976 Mechanism first reported by CertiK. This is what their alert leaves out.
1
7
2,010
Blend's backstop β€” the insurance layer behind every Blend lending pool on Stellar β€” went from $3.92M to $257 in thirteen hours. It started when someone swapped USDC for USDC. Comet, the AMM holding that collateral, never checks token_in != token_out. Neither does Balancer V1, which it forks β€” and Balancer is fine anyway, because `Record storage` makes both names alias one slot, so `+in` and `βˆ’out` compose. Comet's Rust port reads a copy of the map entry and writes both back (pool.rs:202-203). The second set discards the first. The recorded reserve falls by the full amount_in while the real balance rises. Understate a reserve, deposit into it, and the pool mints LP shares out of nothing. 36 flash-loan loops. 53 minutes. 717,518.92 USDC. The trail is unusually clean, because the attacker's account lived 88 minutes: created by a HitBTC withdrawal at 03:25 UTC, seeded with 30,282 USDC from Binance, 36 exploit txs from 03:51 to 04:44, then 500,000 + 247,800.9234056 USDC to NEAR Intents and account_merge. 747,800.92 out minus 30,282 in. That is the entire P&L. Then nobody paused the pool. Six and a half hours later two more addresses replayed the identical bug β€” 355 further transactions until 16:56 UTC β€” and took the remaining 73.9M BLND. BLND is down 92.6%. Blend V2's backstop holds 99.925% of the pool's LP shares. It is still auto-depositing BLND emissions into the empty pool: 4,032 BLND this morning. Audited by OtterSec, January 2024. 11 findings, 0 critical. The bug shipped 844 days ago.
1
249
PT-reUSD cascade, Ethereum, 25 Aug DeFiLlama books this as a $920,000 hack on Steakhouse. Steakhouse lost nothing. The wallet named as the attacker went $677 down. A contract deployed 2h37m earlier took $909,546. $36.13M was liquidated in 13m36s β€” 04:37:47 to 04:51:23 UTC β€” across two Morpho PT-reUSD-10DEC2026 markets. What the borrowers paid is exact, not an estimate: Morpho fixes seized Γ— price = repaid Γ— LIF, so the penalty is repaid Γ— (LIFβˆ’1), and at LLTV 0.915 the LIF is 1.026167265. 35,188,279.71 USDC Γ— 0.0261673 = 920,781.05 944,024.27 USDT Γ— 0.0261673 = 24,702.53 total 945,483.58 The registry's $920,000 is the USDC leg alone, rounded down to the thousand. The USDT leg is not in it. THE PRICE MOVER MADE NOTHING 0x854e3f3b…690d took in 1,000,000 USDT at 02:18:35 and walked out with 999,323.12 DAI at 06:13:59. Net βˆ’$676.88. In between: ten swapExactSyForYt calls on Pendle, 04:28:47 to 04:36:35. Every other token it touched nets to zero. It had rehearsed the same trade the previous afternoon, 24 Aug 12:56–13:49. THE MONEY WENT SOMEWHERE ELSE 0x51a453d6…AB5e is a proxy deployed 25 Aug 01:51:47 β€” on the fourth attempt, after three failed deploys the evening before. It was test-fired at 02:59:47 for 0.02 USDT on a different PT market. Then it repaid 34,758,941.56 of the cascade's 36,132,303.98 in 13 transactions: 96.2%, and $909,546 of the $945,484. Its deployer was funded 3 ETH at 24 Aug 07:53:35 β€” 4m24s and 17 nonces after the price mover's own funding, from the same wallet. That wallet is a busy withdrawal address that serves everybody, so it is not proof of one owner. The ordering is what clusters these: three single-purpose addresses funded inside five minutes, one rehearsing a price move, one building a bot for it. THE ORACLE CAME BACK 0.970991 at 04:28 β†’ 0.951100 at 05:00 β†’ 0.968416 by evening. A βˆ’2.05% excursion, fully retraced inside 90 minutes. The money did not retrace with it. THE CURATOR'S ACCOUNT, CHECKED Steakhouse says no lender was affected and no bad debt was incurred. Both hold: badDebt is 0 on both markets, and Smokehouse USDC's share price rose straight through the cascade, 1.124268 β†’ 1.124347. It also says its systems withdrew liquidity from the affected markets. One tx at 06:03:59 took the USDC position from 3,584,021.40 to zero and pulled 27.9% of the USDT position β€” 72m36s after the last liquidation. Full exposure was back by 08:09:23. The other lenders did not come back. Market supply: 77,968,058 β†’ 62,206,232 USDC, βˆ’20.2%, while Steakhouse's own line is flat at βˆ’1.8%. The $920,781 came out of 19 leveraged PT positions, 14 of them plain EOAs. The three largest paid $340,458, $288,105 and $178,835 of it. etherscan.io/address/0x51a45…
1
1
1
378
Addresses price mover 0x854e3f3b521dbae34cb111ebef0dce41d8b5690d liquidator 0x51a453d677396F62fbb1dff9925a205fa96fAB5e its deployer 0xbcea1aacaf365061dc29510dcf3bd544e16e566f capital wallet 0xd67d8f6b6ba0a97f043305f6b6f5a8ed1a247f44 oracle 0x217d6DdCDB95112C51657F6270e8C079CFDB51f0 markets USDC 0x1e9d614631a7df0ec07fb05b2c8cb2491575fd1a63a33bf187a6afb295a4fc64 USDT 0x6acd18854e43f93f5a90446004c35c72a68af1ad99f08cb247782ce6457914ca first big liquidation, 04:38:23, 11,010,095.48 USDC etherscan.io/tx/0xe1bfa2ef3a… the 06:03:59 de-risking tx etherscan.io/tx/0x8ef463f605…
97