
Date: September 30, 2026
Chain: Ethereum
Loss: 5.3352 ETH, about $14,300
Class: first-deposit bonus paid out twice, with no cap on ETH withdrawn
At 03:27:35 UTC on September 30, 2026, a contract borrowed 53.355703172210117028 WETH from Balancer, spun up a fresh address, and deposited that much ETH into MUSystem. The deposit came straight back as a 32.253522567601017211 ETH bonus refund, and a withdrawal right after returned another 21.502348378400678141 ETH, 0.400167773791578324 ETH more than went in. The contract then did the same thing fifteen more times from fifteen more new addresses, repaid Balancer, and sent 5.9475 ETH to the wallet that started it.
By the end of that block MUSystem, a contract known on-chain as Mutual Uniting System, had lost its entire balance of 5.3352 ETH, about $14,300. The contract handed out its first-deposit bonus twice, once as an immediate ETH refund and once as part of the balance a depositor could later withdraw, and nothing capped what came back at what had gone in.
MUSystem is a mutual-savings style contract whose known deployments on Etherscan date back to 2018, and its token carries the symbol MUS and the name Mutual Uniting System. Participants deposit ETH and receive an allocation they can redeem later, and new entrants get a first-deposit bonus meant to reward joining. The contract that was drained, at 0x9bDF...9364, is unverified on Etherscan, so the DeFiHackLabs contributor who reproduced the attack identified its logic by decompiling the bytecode and checking the result against the real transaction's internal-call trace.
Both deposit() and withdraw() were open to anyone, with no owner check or admin role in the path, which meant any address could walk in as a brand-new depositor and qualify for the bonus.
According to the reproduction, deposit() did two things with the first-deposit bonus. It sent the bonus back to the caller as ETH right away, and it also credited the same bonus into the depositor's redeemable MUS allocation. withdraw() then paid out against that allocation, with no check tying the total ETH a depositor had received, across the refund and the withdrawal together, to the ETH they had actually put in.
Picture a shop that gives every first-time customer a gift card and also adds the same amount to their account balance. Each piece of logic looks reasonable on its own, and the shop only loses money when someone notices both happen for the same purchase and starts arriving as a new customer every few minutes.
Any value a contract pays out has to be counted in exactly one place, and the safest backstop is a hard rule that no participant can ever take out more than they put in plus what they've legitimately earned. Bonuses, referral rewards and first-deposit multipliers deserve that rule as much as core transfers do, because they're the paths that move value without a matching deposit.
The attacker's wallet, 0x1a08...98E5, was funded through RAILGUN and received 14.37 ETH from a Relay solver at 03:10:59 UTC on September 30. Seventeen minutes later, in block 26087602, it deployed an attack contract at 0xD1a7...e988, sent it 10.7 ETH, and called it three more times, all in the same block. The first of those calls created 16 contracts, each a brand-new address that counted as a first-time depositor, and ran one deposit and one withdrawal through each before repaying the 53.36 WETH Balancer flash loan. The second ran another 16 cycles the same way.
DeFiHackLabs found that the trick depended on timing as well as fresh addresses. Withdrawals paid out from the current round of pooled deposits, so the attack only turned a profit after earlier transactions in the same block had filled that round, and a single cycle replayed one block earlier loses money. Across the attack block, MUSystem's own standing balance of 5.3352 ETH went to zero, with the rest of each payout coming from other users' same-block deposits. Blockscout shows the attack contract paying the attacker's wallet 13.89 ETH across the four transactions in that block, against the 10.7 ETH the wallet had put in. SlowMist's alert valued the drain at about $36,900, a figure that lines up with that 13.89 ETH gross, including the 10.7 ETH the attacker supplied itself. The loss to MUSystem was its 5.3352 ETH balance, about $14,300 at Blockscout's rate of $2,684.71 per ETH for that block.
On October 8, between 12:03 and 12:08 UTC, the attacker's wallet sent 17.5 ETH to Tornado Cash in thirteen deposits.
Olympix reads a contract the way an attacker would, as states, transitions and entry points, and it takes in the context around the code, such as what a bonus is meant to reward, to infer the invariants the contract depends on but never writes down. In MUSystem the state that matters is how much ETH each participant has put in and how much they've taken out, and the entry points that change it are deposit() and withdraw(), both callable by anyone.
Olympix's static analysis surfaces the signal: one computed value, the first-deposit bonus, applied to two separate outflows in the same function, an immediate ETH refund and a redeemable allocation, with no aggregate bound on what a caller can receive. Olympix has flagged this class before in other codebases. From that signal the engine narrows from every path, to the feasible ones, to the ones that reach the invariant, which here is plain: the ETH a participant gets back can never exceed the ETH they deposited plus the returns the scheme actually promises.
BugPoCer turns that rule into a target. With Counterexample-Guided Invariant Refutation it models the pool, the current round and a stream of depositors, then executes sequences through deposit() and withdraw() from fresh addresses until one participant walks away with more than they put in. A large first deposit into a funded round does it in a single cycle. BugScout reaches the same functions from the other side, starting at the double-credited bonus and trying known accounting attacks, and symbolic execution sits under both. The counterexample BugPoCer returns is the concrete sequence of state changes, the minimal conditions that trigger it, including the funded round, and a generated Forge test that replays it, which is the September 30 cycle produced in development instead of on mainnet. Run automatically in development, at every merge and before release, that check catches a bonus path the moment it's added.
MUSystem's loss came from generosity written in two places, a bonus refunded and the same bonus stored for later. For builders adding incentives to a deposit flow, the habit worth keeping is to trace every unit of value from where it enters to every place it can leave, and to enforce the ceiling in code. If you'd like to see how Olympix traces those flows through your contracts and returns a runnable counterexample wherever value leaves twice, book a technical walkthrough.
Protocol: MUSystem (Mutual Uniting System, symbol MUS)
Chain: Ethereum
Date: September 30, 2026, 03:27:35 UTC (block 26087602)
Loss: 5.3352 ETH, about $14,300 (the contract's full balance per Blockscout; SlowMist's ~$36,900 counts the attacker's 13.89 ETH gross)
MUSystem contract (victim, unverified): 0x9bDF...9364
Attacker EOA: 0x1a08...98E5
Attack contract: 0xD1a7...e988
Exploit tx (16 cycles, 5.9475 ETH to attacker): 0xfe28...0392
Exploit tx (16 cycles): 0xaa17...9ec6
Exploit tx: 0x905a...83fe
Block: 26087602
Flash loan source: Balancer V2 Vault 0xBA12...F2C8
DeFiHackLabs: MUS_exp.sol proof of concept
Coinfomania: MUSystem Suffers $36.9K Loss Due to Exploit, Says SlowMist