How an Attacker Drained $128M from Balancer Through Rounding Error Exploitation

How an Attacker Drained 8M from Balancer Through Rounding Error Exploitation

On November 3, 2025, an attacker exploited an arithmetic precision (rounding) vulnerability in Balancer V2’s ComposableStablePool _upscaleArray function and used 65+ micro-swaps inside atomic batchSwap transactions to drain $128.64 million across six networks. The exploit contract leveraged Vault internal balances and a constructor-based attack to accumulate funds, later withdrawing them to a recipient address. #ComposableStablePool #BalancerV2 #FixedPoint.mulDown

Keypoints

  • The attacker exploited a rounding error in the _upscaleArray scaling path (FixedPoint.mulDown) causing large relative precision loss when balances hit 8–9 wei boundaries.
  • Precision loss propagated to the StableSwap invariant D, artificially lowering BPT price (D/totalSupply) and enabling profitable arbitrage.
  • The exploit ran 65+ micro-swaps within atomic batchSwap transactions to compound tiny rounding errors into catastrophic invariant manipulation.
  • The exploit contract (0x54B53503c0e2173Df29f8da735fBd45Ee8aBa30d) executed the theft in its constructor, crediting internal Vault balances before withdrawing.
  • InternalBalanceChanged events show the exploit accumulated 6,586 WETH + 6,851 osETH + 4,259 wstETH across targeted pools; subsequent manageUserBalance calls withdrew funds to recipient 0xAa760D53541d8390074c61DEFeaba314675b8e3f.
  • The attack targeted multiple pools atomically via the Balancer Vault (0xBA12222222228d8Ba445958a75a0704d566BF2C8), demonstrating shared-liquidity risk propagation.
  • Despite audits, the vulnerability persisted because testing did not account for adversarially crafted, cumulative batch operations that amplify tiny rounding errors.

MITRE Techniques

  • [T1608] Exploit Public-Facing Application – The attacker exploited a mathematical vulnerability in Balancer V2’s ComposableStablePools by calling batchSwap sequences that compound rounding errors (“the vulnerability exploited arithmetic precision loss in pool invariant calculations”).
  • [T1598] Abuse Elevation Control Mechanism – The attacker used Vault internal balance accounting to claim ownership of tokens by manipulating internal accounting states (“the Vault’s accounting system now recognized the exploit contract as the owner of these balances”).
  • [T1486] Data Encrypted for Impact (economic manipulation) – The attacker depressed BPT price via compounded precision loss to extract value through mint/redeem arbitrage cycles (“reduced D directly lowers BPT price, creating arbitrage opportunities … Mint or purchase BPT at the suppressed price, then immediately redeem”).
  • [T1059] Command and Scripting Interpreter (Smart Contract Constructor Execution) – The exploit executed during contract deployment with constructor running 65+ micro-swaps to perform the attack atomically (“the constructor automatically executed the rounding error exploitation, targeting two Balancer pools simultaneously”).
  • [T1078] Valid Accounts (use of legitimate contract calls) – The exploit used legitimate Vault functions (batchSwap, manageUserBalance) and UserBalanceOp structures to move funds without direct token transfers (“UserBalanceOp has sender equal to the exploit contract address because the contract legitimately owns the funds”).

Indicators of Compromise

  • [Contract Address] Exploit contract and actors – 0x54B53503c0e2173Df29f8da735fBd45Ee8aBa30d (exploit contract), 0x506D1f9EFe24f0d47853aDca907EB8d89AE03207 (deployer), 0xAa760D53541d8390074c61DEFeaba314675b8e3f (recipient).
  • [Vault Address] Targeted protocol contract – Balancer Vault 0xBA12222222228d8Ba445958a75a0704d566BF2C8 (shared liquidity gateway used in exploit).
  • [Transaction Hashes] Key transactions – 0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742 (constructor / theft), 0xd155207261712c35fa3d472ed1e51bfcd816e616dd4f517fa5959836f5b48569 (withdrawal).
  • [Events / Balances] Stolen asset evidence – InternalBalanceChanged entries showing +6,586 WETH, +6,851 osETH, +4,259 wstETH (and aggregated $128.64M across six networks).
  • [Function Signatures] Exploit-specific functions – constructor executed batchSwap sequences and function 0x8a4f75d6 used to call vault.manageUserBalance for withdrawal.


Read more: https://research.checkpoint.com/2025/how-an-attacker-drained-128m-from-balancer-through-rounding-error-exploitation/