Fluid
An attacker compromised the operational keys that propose and approve Fluid's reward payout lists, then used them to approve self-serving reward lists and claim with empty proofs across three chains. In total about 125,109 FLUID and 51,946 GHO, plus a little cbBTC (about $225,000), were taken from Fluid's reward distributors on Ethereum, Base, and Arbitrum. Fluid's lending markets, vaults, DEX, and user deposits were not affected. The Layer 2 proceeds were bridged back to Ethereum, swapped for ether, and about 142.6 ETH was routed into Tornado Cash. Fluid later removed the compromised keys and moved the remaining reward funds to safety. A separate, much larger movement of roughly 70 to 110 million dollars out of Fluid in the days after was depositors withdrawing their own funds, a confidence driven bank run, not a second hack.
Our pre-hack assessment of Fluid flagged operational security as its single weakest area, the lowest-scoring layer in the breakdown. The exact failure mode, privileged operational keys that could be turned into a payout without a second independent custodian or a waiting period, was already what our score was warning about. The exploit confirmed that warning rather than contradicting it.
The attacker controlled Fluid's compromised reward proposer key and approver key, approved a fake reward list, then claimed from the FLUID distributor and GHO distributor into their wallet, swapped the tokens for ether, and routed the proceeds into Tornado Cash.
Safe. User deposits, lending markets, vaults, and DEX liquidity were not affected.
Both reward signers were key-compromised. The attacker called proposeRoot then approveRoot on the distributors across Ethereum, Base and Arbitrum, set self-serving roots, and claimed with empty proofs. No contract was broken.
Full forensic detail
Step-by-step reconstruction, root cause, counterfactuals, remediation, and disclosure timeline.
Exploit anatomy
claim(address,uint256,uint8,bytes32,uint256,bytes32[],bytes)tx:0x6f47dd16...3b0e94swap(...)executeV1(...)tx:0x5240aca9...5847e8Root cause
Fluid's reward system uses a two-key control on Ethereum: a proposer key submits a Merkle root of reward allocations, and a separate approver key approves it before users can claim. Both of these were dedicated single-purpose operational signers active since September 2024 (proposer 0x4f104710, approver 0x85dc44e0). The attacker obtained both private keys and therefore controlled both halves of the two-step control. They proposed a single-leaf root paying themselves, approved it with the second key, and claimed with an empty Merkle proof (valid because root equals leaf for a one-entry tree) and empty signature. No smart contract was bypassed, no Merkle verification was broken, no oracle or governance was manipulated. The failure is operational key custody: privileged reward-approval keys were held in a way that allowed a single compromise to take both roles, and there was no timelock between approval and claim to give defenders a reaction window. The drained contracts are reward distributors only; core Fluid lending markets, vaults, and DEX liquidity were never in scope of these keys.
Prevention analysis
A delay of even a few hours between approval and payout would have turned a 24-second smash-and-grab into a detectable event with a reaction window. The team caught the compromise within ten hours, so a timelock alone would likely have prevented most of the loss.
A single key compromise becomes insufficient. The attack needed both keys at once; independent threshold custody on each role removes the single-extraction path entirely.
A cap on how much a single claim or cycle can release would have bounded the loss well below the full reward balance, regardless of who held the keys.
Similar incidents
Operational private-key compromise enabling a unilateral drain of protocol-adjacent wallets. Same root cause: privileged operational keys held without multisig or threshold custody.
Operational key compromise (social engineering plus blind signing) enabling unilateral control of privileged actions. Same class: weak operational key security on a privileged role.