This is a lower bound: only assets with reliable historical USD prices are counted, so the actual loss may be higher.
0x6caa65b3fc5c8d4c7104574c3a15cd6208f742f9ada7d81ba027b204731377050x7012af43f8a3c1141ee4e955cc568ad2af59c3faArbitrum0xceaf1cbf0cfdd1f7ea4c1c850c0bc032a60431dbArbitrum0x0a4b2e37bfef8e54dea997a87749a403353134e8Arbitrum0xc7d2e96ca94e1870605c286268313785886d2257Arbitrum0x4771522accac6fecf89a6365ceaf05667ed95886Arbitrum0x9847d09cb0eea77f7875a6904bfa22ae06b34cceArbitrumAt Arbitrum block 206219812, transaction 0x6caa65b3fc5c8d4c7104574c3a15cd6208f742f9ada7d81ba027b20473137705 let an unprivileged adversary convert protocol-controlled Yield Strategy balances into attacker-owned assets. The sending EOA was 0x1abe06f451e2d569b3e9123baf33b51f68878656, and it called attacker contract 0xd775fd7b76424a553e4adce6c2f99be419ce8d41, which used a zero-fee Balancer flash loan plus public Yield Strategy and Uniswap V3 entrypoints.
The root cause is a shared accounting flaw in Yield Strategy: public mint and mintDivested treat the strategy contract's own token balance delta as a fresh deposit, while public burn and burnDivested burn the strategy contract's own share balance and send the redeemed assets to an arbitrary caller-selected recipient. That combination let the attacker stage balances on strategy contracts, trigger mint and burn on those self-held balances, and redirect the resulting assets and shares to the attacker.
Yield Strategy instances are ERC20 share tokens over either divested base assets or invested pool tokens. The contract keeps cached accounting in baseCached and poolCached, but the public mint paths do not ask who transferred assets in. Instead, they infer the deposit from the strategy contract's live token balance minus the cached balance.
The burn paths have the symmetric problem. They do not burn the caller's strategy balance. They burn _balanceOf[address(this)], so any strategy-share tokens that have been moved onto the strategy contract itself become redeemable by any external caller.
The incident touched six verified Arbitrum strategy instances:
0x7012af43f8a3c1141ee4e955cc568ad2af59c3fa (YSUSDC6MMS)0xceaf1cbf0cfdd1f7ea4c1c850c0bc032a60431db (YSUSDC6MJD)0x0a4b2e37bfef8e54dea997a87749a403353134e8 (YSETH6MMS)0xc7d2e96ca94e1870605c286268313785886d2257 (YSETH6MJD)0x4771522accac6fecf89a6365ceaf05667ed95886 (YSDAI6MMS)0x9847d09cb0eea77f7875a6904bfa22ae06b34cce (YSDAI6MJD)Because the relevant functions were public and the flash-loan liquidity was public, the opportunity was permissionless and therefore ACT.
This is an ATTACK-class incident caused by unsafe self-balance accounting in a public mint-and-burn flow. The critical invariant is that only balances intentionally supplied for a caller's own mint or burn should become redeemable by that caller. Yield Strategy breaks that invariant in both directions: it treats unsolicited balances on the contract as a deposit, and it treats the contract's own share balance as burnable by any caller.
The vulnerable behavior is visible directly in the shared strategy implementation:
// Yield Strategy shared implementation
function mint(address to) external isState(State.INVESTED) returns (uint256 minted) {
uint256 poolCached_ = poolCached;
uint256 deposit = pool.balanceOf(address(this)) - poolCached_;
poolCached = poolCached_ + deposit;
minted = _totalSupply * deposit / poolCached_;
_mint(to, minted);
}
function burn(address to) external isState(State.INVESTED) returns (uint256 poolTokensObtained) {
uint256 burnt = _balanceOf[address(this)];
_burn(address(this), burnt);
poolTokensObtained = poolCached * burnt / _totalSupply;
pool.safeTransfer(address(to), poolTokensObtained);
}
function mintDivested(address to) external isState(State.DIVESTED) returns (uint256 minted) {
uint256 baseCached_ = baseCached;
uint256 deposit = base.balanceOf(address(this)) - baseCached_;
baseCached = baseCached_ + deposit;
minted = _totalSupply * deposit / baseCached_;
_mint(to, minted);
}
function burnDivested(address to) external isState(State.DIVESTED) returns (uint256 baseObtained) {
uint256 burnt = _balanceOf[address(this)];
baseObtained = baseCached * burnt / _totalSupply;
_burn(address(this), burnt);
base.safeTransfer(to, baseObtained);
}
The first breakpoint is deposit inference from balanceOf(address(this)) - cached. The second breakpoint is redemption of _balanceOf[address(this)] to arbitrary to. Once those two behaviors exist together, any caller who can stage tokens or shares on the strategy contract can convert them into attacker-owned value.
The reconstructible pre-state sigma_B is Arbitrum immediately before block 206219812 transaction 0x6caa65b3fc5c8d4c7104574c3a15cd6208f742f9ada7d81ba027b20473137705. Relevant public state included the six strategy contracts above, Balancer Vault liquidity, and the Uniswap V3 route later used for settlement. No privileged state or private input was required.
The attacker executed a single adversary-crafted transaction. It first obtained a zero-fee Balancer flash loan of 1 wei WETH, 30000000000000000000000 DAI, and 400000000000 USDC. It then staged base tokens or strategy-share tokens onto victim strategy contracts and invoked the public mint and burn entrypoints in the same transaction.
For divested strategies, the attacker transferred base tokens to the strategy contract and then called mintDivested, causing the contract to mint shares based on the strategy's own observed base-token balance increase. For invested strategies or peer legs, the attacker transferred strategy shares to another strategy instance, called mint so the self-held share balance was treated as an inbound deposit, and then called burn so the strategy contract burned its own balance and returned the resulting assets or shares to the attacker.
The result was unauthorized redemption across multiple strategy pairs. The balance-diff artifact shows the attacker contract finishing with positive balances in every affected asset class, including direct base-token profits and large stolen strategy-share balances:
{
"attacker_usdc_delta": "91013962",
"attacker_dai_delta": "15857377675310499790",
"attacker_ysusdc6mms_delta": "94736361021",
"attacker_ysusdc6mjd_delta": "32686797817",
"attacker_yseth6mms_delta": "7260287412439004928",
"attacker_yseth6mjd_delta": "5839348176598723073",
"attacker_ysdai6mms_delta": "7527230299779928497195",
"attacker_ysdai6mjd_delta": "4498212130546008547596"
}
The paired victim strategy contracts were correspondingly depleted to dust-level or near-dust balances in the affected share tokens. For the representative USDC peer legs, the collected balance diff shows:
[
{
"holder": "0x3b4ffd93ce5fcf97e61aa8275ec241c76cc01a47",
"before": "95117907443",
"after": "30421236",
"delta": "-95087486207"
},
{
"holder": "0x33e6b154efc7021dd55464c4e11a6afe1f3d0635",
"before": "32524318859",
"after": "435262",
"delta": "-32523883597"
}
]
The success predicate is therefore satisfied in both monetary and non-monetary terms: the attacker made direct profit in USDC and DAI, and it also extracted unauthorized ownership of multiple Yield Strategy share balances by abusing public strategy accounting.
The attacker lifecycle has three stages.
First, the attacker funded the exploit with a public Balancer flash loan. The transaction metadata and trace tie the initiating EOA 0x1abe06f451e2d569b3e9123baf33b51f68878656 to attacker contract 0xd775fd7b76424a553e4adce6c2f99be419ce8d41, which received the flash-loaned assets and ran the exploit logic.
Second, the attacker abused public strategy mint and burn paths across six strategy instances. The essential flow was:
mint or mintDivested so the strategy contract interprets its own balance increase as a caller deposit.burn or burnDivested so the contract burns _balanceOf[address(this)] and sends redeemed assets or shares to the attacker.Third, the attacker settled the transaction by swapping part of the extracted WETH into USDC, repaying the Balancer principals, and keeping the residual gains. The incident-level profit predicate in root_cause.json records a direct USDC remainder of 91013962 after loan repayment, while the balance-diff artifact also records 15857377675310499790 DAI and the six stolen strategy-share balances left in attacker custody.
The exploit was entirely contained in one transaction and required no privileged calls, no ownership transfer, and no attacker-specific off-chain artifact beyond normal transaction construction.
The measured losses from root_cause.json and the collected balance diff are:
USDC: 91013962 base units (decimal=6)DAI: 15857377675310499790 (decimal=18)YSUSDC6MMS: 94736361021 (decimal=6)YSUSDC6MJD: 32686797817 (decimal=6)YSETH6MMS: 7260287412439004928 (decimal=18)YSETH6MJD: 5839348176598723073 (decimal=18)YSDAI6MMS: 7527230299779928497195 (decimal=18)YSDAI6MJD: 4498212130546008547596 (decimal=18)These losses show that the incident was not limited to a single profit token. The attacker extracted direct base assets and retained large share positions representing additional protocol-controlled value. The affected parties were the six Yield Strategy instances listed above, whose balances and peer-strategy positions were consumed by the unauthorized mint-and-burn sequence.
0x6caa65b3fc5c8d4c7104574c3a15cd6208f742f9ada7d81ba027b204731377050x1abe06f451e2d569b3e9123baf33b51f688786560xd775fd7b76424a553e4adce6c2f99be419ce8d410xBA12222222228d8Ba445958a75a0704d566BF2C8Strategy.sol functions mint, burn, mintDivested, burnDivested