Calculated from recorded token losses using historical USD prices at the incident time.
0xab486012f21be741c9e674ffda227e30518e8a1e37a5f1d58d0b0d41f6e765300x3f2d1bc6d02522dbcdb216b2e75edddafe04b16fEthereum0xebe0d1cb6a0b8569929e062d67bfbc07608f0a47Ethereum0x26267e41ceca7c8e0f143554af707336f27fa051EthereumRari Fuse Pool 127 was drained in Ethereum transaction 0xab486012f21be741c9e674ffda227e30518e8a1e37a5f1d58d0b0d41f6e76530 at block 14684814. The attacker used a Balancer flash loan of 150,000,000 USDC and 50,000 WETH, deployed two helper borrowers, and repeatedly borrowed ETH from fETH-127 while reentering the protocol during the ETH payout. That reentrancy let each helper remove its fUSDC-127 collateral-market membership before Fuse persisted the new ETH debt, after which the helper redeemed the same USDC collateral and kept the borrowed ETH debt outstanding.
The root cause is a checks-effects-interactions violation in Fuse Pool 127's CEther borrow flow. CEther.doTransferOut sends ETH to the borrower before the borrow balance is durably visible to Comptroller collateral checks, so a borrower contract can call Comptroller.exitMarket(fUSDC-127) from its receive hook and then redeem collateral that should still be locked.
Fuse Pool 127 used a Compound-style Comptroller at 0x3f2d1bc6d02522dbcdb216b2e75edddafe04b16f to track market membership and collateralization across fUSDC-127, fUSDT-127, fFRAX-127, and fETH-127. A user that is still a member of a collateral market must pass redeemAllowedInternal, which performs a hypothetical liquidity check before allowing collateral withdrawal.
The borrowed ETH market is fETH-127 at 0x26267e41ceca7c8e0f143554af707336f27fa051. Unlike an ERC-20 cToken, its underlying transfer path is a raw ETH call:
function doTransferOut(address payable to, uint amount) internal {
(bool success, ) = to.call.value(amount)("");
require(success, "doTransferOut failed");
}
That means a contract borrower can execute arbitrary logic during the borrow payout itself. In the exploit transaction, the attacker used that capability to call back into the shared Comptroller before Fuse had finished the borrow operation.
The vulnerability is borrow-time cross-market reentrancy. Fuse expects an account with an outstanding borrow to remain a member of sufficient collateral markets until the debt is repaid, but fETH-127 exposes an intermediate state where the borrower has already received ETH and can reenter before the debt is fully accounted for. During that window, Comptroller.exitMarket reads the borrower's stale account snapshot and sees zero debt in the borrowed market. Because exitMarket only blocks when amountOwed != 0, it incorrectly permits the borrower to leave the fUSDC-127 collateral market.
Once membership is deleted, redeemAllowedInternal takes the fast path that bypasses the liquidity check for non-members. The borrower can then redeem all previously supplied USDC even though the ETH borrow remains outstanding. Repeating the same sequence across two helper contracts drains the ETH liquidity, and the attacker then uses a fresh fETH-127 collateral position to borrow the remaining stablecoin cash from the pool.
The critical victim-side code path is Comptroller.exitMarket:
(uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);
require(oErr == 0, "exitMarket: getAccountSnapshot failed");
if (amountOwed != 0) {
return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);
}
If amountOwed is still zero, the function continues and deletes market membership. redeemAllowedInternal then explicitly bypasses collateral checks for non-members:
if (!markets[cToken].accountMembership[redeemer]) {
return uint(Error.NO_ERROR);
}
The exploit works because the borrow path exposes a stale snapshot during an external call. The collected Fuse source for borrowFresh shows the interaction ordering:
doTransferOut(borrower, borrowAmount);
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
In the deployed CEther implementation, doTransferOut performs to.call.value(amount)(""), so the borrower fallback runs before the function has safely completed. The seed trace for the exploit transaction shows that exact sequence: the helper borrows from fETH-127, receives ETH, invokes Comptroller.exitMarket(fUSDC-127) from the callback, then later redeems the full 150,000,000 USDC collateral. The same trace later shows the second helper repeating the pattern after the attacker replenishes fETH-127 cash with a 50,000 ETH deposit.
The safety invariant is straightforward: an account with positive borrow exposure must not be able to drop required collateral membership or redeem pledged collateral until the debt is fully reflected in Comptroller risk checks. Fuse breaks that invariant because the borrower's externally callable window appears before the collateralization state is coherent across markets.
The attacker EOA 0x6162759edad730152f0df8115c698a42e666157f submitted the single exploit transaction. The trace shows the attacker-controlled orchestrator 0x32075bad9050d4767018084f0cb87b3182d36c45 receiving a Balancer flash loan of USDC and WETH, then deploying helper borrower 0x03296d34fd6b3619a75860f44a0d2c68336708e7.
That first helper entered the fUSDC-127 market, minted against the transferred 150,000,000 USDC, borrowed the entire preexisting fETH-127 cash balance, and during the ETH payout callback called exitMarket(fUSDC-127). After the borrow returned, the helper redeemed the full USDC collateral and swept both ETH and USDC back to the orchestrator. The attacker then deposited 50,000 ETH into fETH-127, entered that market as collateral, and borrowed the remaining cash from fUSDC-127, fUSDT-127, and fFRAX-127.
Next, the orchestrator deployed a second helper 0x4ec88aa13b789fa31e939124a3384dce9d8030e8, repeated the same borrow-exit-redeem sequence against fETH-127 and fUSDC-127, redeemed residual attacker-owned fETH-127 collateral, repaid the Balancer flash loan, and transferred the drained ETH, USDC, USDT, and FRAX to profit receiver 0xe39f3c40966df56c69aa508d8ad459e77b8a2bc1.
The collected balance diff confirms that the exploit drained the victim markets and credited the attacker-controlled receiver with:
1,977.579153781557429247 ETH, encoded on-chain as "1977579153781557429247"7,144,266.341363 USDC, encoded on-chain as "7144266341363"132,959.900829 USDT, encoded on-chain as "132959900829"776,937.058467725803492533 FRAX, encoded on-chain as "776937058467725803492533"The protocol impact is broader than the immediately transferred balances. After the exploit, the helper borrowers retained uncompensated fETH-127 debt positions that were no longer backed by the redeemed fUSDC-127 collateral, leaving Fuse Pool 127 with bad debt in addition to the drained cash.
0xab486012f21be741c9e674ffda227e30518e8a1e37a5f1d58d0b0d41f6e76530exitMarket and redeemAllowedInternalborrowFresh and doTransferOut