Balancer Callback Drain
Exploit Transactions
0x274c740fb476377fe731d6f7aff0c9dbeee0cac79d3a2256584de76166a206480x830080c09594d75c66f78deccb83c01835aba6ddc2da566e91eca8570df710810xd7e159d1ead5800493fbeb21dfcae23596e736e4b48cdc72d849bd0aab43b8750x902db35e54a12bbc100eb62ecddbdffb0e04bf8327970f5640566fe1cf8e8ac40xa7874f4d57bed8eb80fdef8c4073540cdbb952fd0075fe3e07beb923ed6d03d60xc990268a773cac177eff4340910a8c32d4109a54f39d282a05ced11f58e1a1d50xb6431825b6885d28c0df71365345f4869ce97f126ba6fc8b89ff4b9a507e58820x6a1c269b50fde4318f3fe3679633461044efd55a90cdf05b76acc068d358d99cVictim Addresses
0x79776f9237b686dbffc0a7c629b86d575ca8ca0aArbitrumLoss Breakdown
Similar Incidents
Sentiment Balancer Oracle Overborrow
39%STRAC Callback Drain
31%Themis Oracle Manipulation
31%dForce Oracle Reentrancy Liquidation
31%BSC Callback Auth Drain
31%Paribus Redeem Reentrancy
30%Root Cause Analysis
Balancer Callback Drain
1. Incident Overview TL;DR
On Arbitrum block 443689594, attacker EOA 0xa54408e0084f6b536ae9cbaad08895973d4a31d5 deployed ephemeral contracts and used Balancer Vault flashLoan to invoke the victim helper contract 0x79776f9237b686dbffc0a7c629b86d575ca8ca0a as the flash-loan recipient. The helper then executed attacker-controlled callback data, transferred its WETH and USDC into the attacker receiver, and the receiver forwarded the proceeds to the attacker EOA.
The root cause is an authorization failure in the helper's Balancer flash-loan callback. receiveFlashLoan(address[],uint256[],uint256[],bytes) trusted any callback coming from Balancer Vault and decoded attacker-controlled userData without verifying that the flash-loan request was initiated or approved by the helper owner.
2. Key Background
Balancer Vault flash loans are permissionless. Any EOA or contract can call flashLoan and nominate an arbitrary recipient contract. Under Balancer's standard flow, the Vault then calls that recipient's receiveFlashLoan callback.
The victim is an unverified helper or smart-wallet-style contract at 0x79776f9237b686dbffc0a7c629b86d575ca8ca0a. Its disassembly shows hard-coded addresses for Balancer Vault 0xba12222222228d8ba445958a75a0704d566bf2c8, Aave pool 0x794a61358d6845594f94dc1db02a252b5b4814ad, and owner 0x88229ecb1eb6a526dc7c45940305c2b5f583af89.
The helper did contain direct owner-gated control paths. In the disassembly, the path beginning near offset 0x0342 checks the caller against the hard-coded owner before performing token approvals:
00000342: JUMPDEST
00000343: CALLER
...
0000034c: PUSH32 0x00000000000000000000000088229ecb1eb6a526dc7c45940305c2b5f583af89
0000036e: EQ
0000036f: PUSH2 0x038b
00000372: JUMPI
...
0000038f: PUSH4 0x095ea7b3
That makes the callback path important: it bypassed the helper's intended authorization boundary.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK, not a benign MEV opportunity. The helper exposed a Balancer flash-loan callback that authenticated only the immediate caller, not the strategy initiator. Because Balancer flash loans are public, an unprivileged attacker could ask Balancer to call the helper directly. Once inside receiveFlashLoan, the helper decoded attacker-controlled userData and dispatched attacker-chosen external calls against the helper's own balances. That let the attacker move WETH and USDC out of the helper without ever satisfying the helper's owner checks. The broken invariant is: only the helper owner or an owner-authorized strategy path should be able to transfer or route helper-held assets. The code-level breakpoint is the callback path behind selector 0xf04f2707, which leads into the vulnerable logic around offset 0x0f53.
4. Detailed Root Cause Analysis
The helper's dispatcher routes selector 0xf04f2707 to the Balancer callback logic:
0000004a: PUSH4 0xf04f2707
0000004f: EQ
00000050: PUSH2 0x0323
...
0000033e: PUSH2 0x0f53
00000341: JUMP
The exploit transaction 0x274c740fb476377fe731d6f7aff0c9dbeee0cac79d3a2256584de76166a20648 shows the full permissionless path. The attacker-created wrapper contract deployed a receiver contract and called Balancer Vault flashLoan with the victim helper as recipient and a zero ARB amount. Balancer then invoked:
victim_helper::receiveFlashLoan([ARB], [0], [0], userData)
Inside that callback, the helper transferred its full WETH balance to the attacker receiver and then executed attacker-directed logic on the receiver:
weth::transfer(DrainReceiver, 94000000000000000)
DrainReceiver::fallback()
DrainReceiver::fallback(false, victim_helper)
weth::transfer(attacker, 94000000000000000)
The transaction receipt independently confirms the same asset flow. It records WETH transfer 0x7977... -> 0x8a8a7159... for 0x014df48080e30000, then 0x8a8a7159... -> 0xa54408e0... for the same amount, plus USDC transfer 0x7977... -> 0x8a8a7159... for 0x0bebc200, then onward to the attacker EOA. These transfers are only possible because the callback accepted attacker-controlled userData without binding it to an owner-approved initiator or trusted strategy contract.
The exploit conditions are straightforward and permissionless:
- The helper holds transferable token balances.
- The helper remains callable by Balancer Vault through
receiveFlashLoan. - The attacker can deploy a compatible receiver contract and encode malicious callback data.
With those conditions satisfied, the attack is deterministic.
5. Adversary Flow Analysis
The attacker flow begins with EOA 0xa54408e0084f6b536ae9cbaad08895973d4a31d5, which deployed wrapper contract 0x88bf1390314c22fb1e745910b8b4fcdde8431e8b in tx 0x274c740fb476377fe731d6f7aff0c9dbeee0cac79d3a2256584de76166a20648. The wrapper created receiver 0x8a8a71590d6a8b0bb9213ef55755b1594c66382b, then invoked Balancer Vault flashLoan with recipient 0x79776f9237b686dbffc0a7c629b86d575ca8ca0a.
The on-chain execution sequence is:
- Attacker deploys wrapper and receiver.
- Receiver requests a zero-amount Balancer flash loan with the victim helper as callback recipient.
- Balancer Vault calls
receiveFlashLoanon the helper. - The helper transfers helper-held WETH and USDC into the attacker receiver and executes attacker-controlled sub-dispatch.
- The receiver forwards drained assets to attacker EOA
0xa54408e0084f6b536ae9cbaad08895973d4a31d5.
The same strategy was repeated across later attacker-crafted transactions listed in all_relevant_txs, but tx 0x274c740f... is sufficient to prove the root cause and the ACT exploitability.
6. Impact & Losses
The helper and its owner suffered direct token theft. The collected receipts show aggregate attacker inflows across the exploit set of:
WETH:467987463873607137raw unitsUSDC:200000000raw unitsUSDT:30682753raw unitsARB:35000000000000000000raw units
The victim-side effect in tx 0x274c740f... is visible immediately: the helper's WETH balance is drained to zero and its USDC is transferred into the attacker path. The attacker pays only normal gas costs in ETH, which are materially smaller than the received token value.
7. References
- Exploit tx:
0x274c740fb476377fe731d6f7aff0c9dbeee0cac79d3a2256584de76166a20648 - Victim helper:
0x79776f9237b686dbffc0a7c629b86d575ca8ca0a - Balancer Vault:
0xba12222222228d8ba445958a75a0704d566bf2c8 - Owner address embedded in helper bytecode:
0x88229ecb1eb6a526dc7c45940305c2b5f583af89 - Helper disassembly cited in the package
- Call trace and receipt for tx
0x274c740f..., which show Balancer invoking the helper callback and the subsequent WETH and USDC transfers into the attacker path