WEB3-ABRACADABRA-2025
Web3 · Arbitrum · Abracadabra Money (GmxV2 Cauldron / MIM)
Summary
In late March 2025 Abracadabra.Money lost about $13 million (roughly 6,260 ETH) on Arbitrum when an attacker abused the GMX V2 gmCauldrons that accept GMX GM liquidity tokens as collateral. GMX deposits are asynchronous, so the attacker submitted deposit orders with unsatisfiable minOut values that GMX rejected, returning the input USDC to the cauldron's order/router contract while the cauldron's accounting still counted that pending position as live collateral. Functions such as sendValueInCollateral removed real tokens during liquidation without clearing inputAmount/minOut state, so orderValueInCollateral kept reporting phantom collateral. Inside a single cook() batch the attacker borrowed MIM against this ghost collateral, self-liquidated to pull out the real returned tokens, and reborrowed, while the end-of-cook solvency check still read the stale inflated collateral value and passed. The accounting bypass let the attacker borrow against effectively non-existent collateral and extract MIM.
How to avoid it in your code
- Decrement internal collateral accounting atomically whenever real tokens leave the contract, so liquidation cannot leave phantom collateral behind.
- Treat failed or cancelled async GMX orders as returned funds, clearing inputAmount/minOut and never counting pending orders as live collateral.
- Run the solvency check against freshly recomputed collateral inside cook(), not against cached or pre-action values.
- Disallow self-liquidation that lets a borrower reuse the same collateral across borrow, liquidate and reborrow within one batch.
- Reconcile cauldron internal balances against actual token holdings before approving borrows in async-collateral integrations.
References
Related vulnerabilities
All Web3 →- CRITICALWEB3-BUNNI-2025
On September 2, 2025 Bunni, a liquidity manager built on Uniswap v4, was drained of roughly $8.4 million across Ethereum and Unichain (USDC, USDT, and weETH/ETH) through a rounding error in its withdrawal accounting amplified by flash loans. Bunni's Liquidity Distribution Function (LDF) tracks an 'idle balance' that is rebalanced on every swap, and the withdraw path rounded that balance in the wrong direction under specific conditions. The attacker flash-borrowed millions in USDT and executed a precisely sized sequence of swaps that pushed the pool's spot price back and forth across tick boundaries, triggering the faulty rounding repeatedly; each cycle let them withdraw more tokens than they burned in liquidity (in the USDC/USDT pool the idle balance fell 85.7% while liquidity fell only 84.4%, and that gap was the leak). The bug was application-specific accounting math, not an oracle or price-feed flaw. Unable to fund a secure relaunch, the Bunni team announced on October 23, 2025 that it was permanently shutting down, leaving withdrawals open and relicensing v2 from BUSL to MIT.
- CRITICALWEB3-CETUS-2025
On May 22, 2025 Cetus Protocol, the leading DEX on Sui, was drained of approximately $223M. The root cause was a flawed overflow check: the checked_shlw function in the integer-mate math library built its guard mask as 0xFFFFFFFFFFFFFFFF << 192 instead of 0x1 << 192, so values above 2^192 slipped past the check and the subsequent 64-bit left shift silently overflowed (left shifts do not abort in Move). The flaw lived in get_delta_a, which computes the tokens needed for a liquidity position; under the overflow the numerator wrapped to a tiny value, so the function demanded as little as 1 token unit for an enormous liquidity amount. Using flash swaps (borrowing ~10M haSUI), the attacker opened a tight-range position (ticks [300000, 300200]) and minted a massive amount of liquidity for a negligible deposit, then withdrew real pool reserves. Around $162M was frozen on-chain by Sui validators and eventually returned, while roughly $62M was bridged out to Ethereum. Cetus relaunched after recovering and replenishing affected pool liquidity.
- HIGHWEB3-VOW-2024
On August 13, 2024 the Vow (Vowcurrency) protocol lost about $1.2 million (~452 ETH) when its own admin temporarily misconfigured a price setter and an MEV bot pounced. Vow's usdRateSetter admin key called setUSDRate and changed the VOW-to-vUSD exchange rate from 1 to 100 - the team later said it was testing the rate-setter while preparing a lending pool - then reverted it. The function had no input validation and no rate-change delay or timelock, and the inflated rate was readable on-chain for the window between the two transactions. An attacker-controlled MEV bot, its contract deployed 110 days earlier and funded via Tornado Cash, detected the change and within two blocks swapped VOW into vUSD at the 100x rate, minting roughly 148.7 million vUSD far above its backing, then dumped it for ETH and USDT on Uniswap. The VOW token fell 80-87%. The root cause was an unbounded, unprotected privileged setter exposed without a timelock, turning a careless admin action into instantly exploitable on-chain state.
- CRITICALWEB3-UWULEND-2024
On June 10, 2024, UwU Lend, an Aave-fork lending protocol on Ethereum, lost about $19.3 million, followed by a second ~$3.7 million drain on June 13, 2024 (combined ~$23 million). The root cause was flash-loan oracle manipulation of the sUSDe price feed: the custom sUSDePriceProviderBUniCatch oracle priced sUSDe as the median of 11 sources, 5 of which read instantaneous Curve pool spot prices via get_p (no TWAP/EMA smoothing) across the FRAXUSDe, USDeUSDC, USDeDAI, USDecrvUSD and GHOUSDe pools. Using a roughly $3.8 billion flash loan, the attacker swapped large USDe amounts to suppress the median sUSDe price, set up positions, then reversed the swaps to inflate it, rendering their own leveraged position liquidatable and self-liquidating repeatedly to harvest base assets at favorable rates. Curve explicitly advises against using get_p spot reads for oracles. The June 13 follow-up reused collateral left from the first attack, since sUSDe was not disabled as borrowable collateral.
- CRITICALWEB3-SONNE-2024
On May 14, 2024 Sonne Finance, a Compound v2 lending fork on Optimism, lost about $20 million when an attacker exploited a freshly created, low-liquidity VELO (Velodrome) market. Because market creation and the protective collateral-factor setup were split across timelocked permissionless transactions two days apart, the attacker acted inside the window before the market was safely seeded. The attacker minted the minimum amount of soVELO cTokens (1 wei) and then donated a large quantity of VELO directly to the soVELO contract, inflating totalCash while totalSupply stayed near zero. Since exchangeRate equals (totalCash + totalBorrows - totalReserves) / totalSupply, this empty-market rounding manipulation drove the cToken exchange rate up so the tiny share position was valued as enormous collateral. The attacker then borrowed roughly 265 WETH plus available USDC.e against the over-valued collateral, draining about $20M within about 25 minutes.
- CRITICALWEB3-KYBERSWAP-2023
On November 23, 2023 KyberSwap Elastic was exploited across six chains for over $48M (>$20M Arbitrum, $15M Optimism, $7.5M Ethereum, $3M Polygon, $2M Base, ~$23K Avalanche). The root cause was a rounding-direction bug in the concentrated-liquidity math: estimateIncrementalLiquidity should have rounded delta liquidity up so the final price rounded down, but it used mulDivFloor and rounded delta liquidity down, pushing the computed sqrt price slightly past a tick boundary without legitimately crossing it. Using Aave flash loans, the attacker first swapped to park the price in a liquidity-empty region, calibrated a tight position, then performed extremely precise swaps so the price landed exactly on a tick's sqrt price. This forced _updateLiquidityAndCrossTick to register a crossing in computeSwapStep twice, double-counting the tick's liquidity on the reverse swap and paying out far more output than backed, draining the pools. The attacker later opened negotiations; most funds were not promptly recovered.