A feather sinks a ship – Analysis of the Balancer hack that cost over $100 million.

This article is machine translated
Show original

On November 3, 2025, Balancer v2, a long-established decentralized automated market maker protocol, was attacked, resulting in a loss of approximately $120 million across multiple chains for several projects, including its fork protocol. This further exacerbated the already sluggish DeFi ecosystem.

Authors: Kong & Lisa

Editor: 77

background

On November 3, 2025, Balancer v2, a long-established decentralized automated market maker protocol, was attacked, resulting in losses of approximately $120 million across multiple chains for several projects, including its fork protocol. This further exacerbated the already sluggish DeFi ecosystem. The following is a detailed analysis of this attack by the SlowMist security team:

root cause

In Balancer v2's Composable Stable Pool implementation (based on Curve StableSwap's Stable Math), there is a precision loss issue in the integer fixed-point arithmetic of scaling factors, resulting in small but compounding price differences/errors in token swaps. Attackers can exploit small swaps under low liquidity to amplify this error for significant cumulative profits.

Prerequisites

Before we begin the analysis, we need to understand some key aspects of Balancer in order to comprehend the content of this analysis.

Composable Stable Pools

Composable stable asset pools are token swap pools designed specifically for assets expected to trade at near parity or known exchange rates. Examples include USDC/USDT swapped at a near 1:1 ratio, or WETH/stETH swapped at a known exchange rate.

Balancer Pool Token (BPT)

BPT represents a share in a Balancer pool. Users receive BPT when they add liquidity to the pool, representing their share of liquidity in the pool.

Composability

Liquidity pools allow LPs to swap with liquid assets to improve capital efficiency. For example, swaps can be made between BPT tokens and liquid tokens such as WETH/stETH.

Scaling Factor

Balancer's underlying pools employ a method for managing decimal precision and rounding direction, ensuring that all funds, before entering the pool for calculations, have their precision and decimal rounding direction optimized for the pool's benefit through scaling factors.

Batch Swaps

The bulk swap feature allows users to swap different tokens within the same or multiple pools in a single transaction. The pools use virtual values for internal accounting and settle accounts after the bulk swap is completed.

Attack Analysis

Here, we take two transactions involved in an attack on Ethereum as an example:

Attack transaction: 0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742

Withdrawal transaction: 0xd155207261712c35fa3d472ed1e51bfcd816e616dd4f517fa5959836f5b48569

  1. The attacker first launched an attack transaction through the bulk swap function, using BPT to swap out a large amount of liquidity tokens from the pool, which made the pool's liquidity token reserves very low.
  1. After the pool's liquidity token reserves decreased, the attackers began swapping liquidity tokens (osETH/WETH).
  1. Finally, the liquidity tokens are exchanged back into BPT tokens, and this process is repeated across multiple pools.
  1. After completing the attack transaction, the attacker used a separate withdrawal transaction to call Vault's manageUserBalance function to extract the profits. This transaction was the same one that several analysts had previously mistakenly identified as an attack transaction and analyzed, but it was actually just a normal withdrawal transaction using normal withdrawal logic.
  1. So why can attackers seemingly easily withdraw funds from Vault without paying any tokens through the above operations? Through simple observation, we can find that after the attacker completes the bulk swap, the internal ledger balance of Vault increases, which allows the attacker to directly withdraw these balances from Vault.

Next, we will analyze in detail why attackers can create an out-of-pocket increase in balance without paying any tokens.

Principle Analysis

Based on the attack analysis above, we can see that attackers mainly achieve their gains through three steps:

  1. Use BPT to exchange for liquidity tokens;
  2. Conduct liquidity token swaps;
  3. Exchange liquidity tokens back to BPT.

We first analyze the process of exchanging BPT for liquidity tokens. Since the attacker's exchange type `kind` is 1, the pool uses the attacker's exchange amount as `amountOut` to calculate how much `amountIn` the attacker should provide for the exchange. We won't go into the complex call chain here; we'll directly analyze the underlying `_swapWithBpt` function of the BPT exchange.

The `_swapWithBpt` function first uses the `_upscaleArray` function to scale the token reserve amount in the pool using a scaling factor to ensure consistent price precision and rounding direction. The `_upscaleArray` function performs the specific scaling operation using `FixedPoint.mulDown`. We can quickly see that `mulDown` rounds the calculation result down, i.e., truncates the decimal.

This will cause any decimals in the pool reserves to be truncated during scaling. As we know from prior knowledge, composability pools are token swap pools designed specifically for assets expected to trade at near parity or a known exchange rate. Taking WETH and osETH as an example, there is a known exchange rate between them. Therefore, when calculating the actual osETH reserves, it is necessary to multiply by the exchange rate and then scale to unify the price.

Unfortunately, due to exchange rates, calculating the reserve amount of osETH will inevitably result in a truncated decimal.

This results in the calculated pool reserve balance being lower than expected. Since the price of BPT is calculated by dividing the total price of the pool's liquidity tokens by the total supply of BPT tokens, this error means that the BPT price will be lower than expected.

By exploiting the price difference caused by this error, the attacker would gain a small profit when exchanging liquidity tokens back to BPT tokens in the third step of the bulk swap. However, this is clearly far from the attacker's huge profit, so the key lies in the second step of the bulk swap.

The attacker still uses the exchange type kind 1 when performing liquidity swaps. By directly analyzing the underlying swap function, we can quickly discover that the _swapGivenOut function first performs scaling through the _upscale function:

Similar to the previous `_upscaleArray` function, the scaled value of the user's exchange amount is truncated to a decimal using the `FixedPoint.mulDown` function. This results in the final required amount of input tokens (`amountIn`) being less than expected. This error is negligible if the exchange amount is large, but it can lead to significant deviations if the exchange amount is small.

The attackers did exactly that: in the second step of the bulk swap, they first reduced the balance of osETH in the pool, and then precisely performed a small-scale swap of 17wei of osETH.

The actual balance should be 17.98825094772952 when performing scaling calculations.

However, due to decimal truncation, the final balance is still 17wei, 0.98825094772952. Compared to 17, the loss of precision has already caused a huge deviation. The amountIn of input tokens calculated in this way will also cause a huge deviation.

To ensure that this deviation can be accumulated cyclically, in the second step of the bulk swap, the attacker will swap osETH back to WETH to ensure that there is still enough liquidity for the next small swap.

Since WETH is a currency-pegged token, the scaling in the osETH -> WETH exchange process is done at 1e18, so it will not be affected by the accumulation of previous errors.

Now we can clearly understand the entire attack process:

  1. The attackers reduced the pool's liquidity token reserves by exchanging BPT for liquidity tokens in preparation for small swaps;
  2. This is to prepare for precise control of accuracy errors in small swaps by swapping osETH -> WETH between liquidity tokens;
  3. Accuracy error is accumulated precisely through osETH -> WETH swaps;
  4. Liquidity is restored through the swap of WETH -> osETH between liquidity tokens;
  5. Repeating steps 2-4 continuously amplifies the error;
  6. Exchange liquidity tokens back for BPT tokens to restore liquidity balance;
  7. By exploiting the amplified error from small-amount token swaps, the amount of tokens lost at final settlement is far greater than the amount of tokens needed to be lost in the final settlement, thereby generating huge profits.

MistTrack Analysis

Due to the large number of projects involved, this section only analyzes the main addresses and fund flows in this incident.

1. Address 0xaa760d53541d8390074c61defeaba314675b8e3f

Profitability: Earnings on Ethereum include various tokens such as osETH and USDC.

Transfer details: After exchanging various tokens such as ezETH, weETH, and ankrETH, as well as some osETH, for ETH, the funds were transferred to address 0xf19fd5c683a958ce9210948858b80d433f6bfae2.

Balance status: mainly includes 7,838.3569 WETH and 7,000 ETH.

Initial funding source: address 0x506d1f9efe24f0d47853adca907eb8d89ae03207, its funds come from gas.zip.

Analysis of address 0x506d1f9efe24f0d47853adca907eb8d89ae03207 reveals the following transaction details in gas.zip:

This address continuously dispersed ETH from Arbitrum across multiple blockchains before launching attacks. Tracing further back, the funds in address 0x506d1f9efe24f0d47853adca907eb8d89ae03207 can initially be traced back to Tornado Cash.

  • Tornado Cash → 0x86fedad11c4765700934639f1efe1fc01355c982: 100 ETH + 0.1 ETH withdrawn from Tornado Cash were transferred to this address.
  • 0x86fedad11c4765700934639f1efe1fc01355c982 → 0x766a892f8ba102556c8537d02fca0ff4cacfc492: Transfer 15 ETH.
  • 0x766a892f8ba102556c8537d02fca0ff4cacfc492 → Cross-chain and perform gas.zip operation: Transfer 5 ETH from Ethereum to Arbitrum and to address 0x506de24d01e6c8623307c9ff5e3c8a945b553207.

2. Address 0xf19fd5c683a958ce9210948858b80d433f6bfae2

Profitability: This address is a core relay node, receiving funds from multiple chains and upstream addresses.

Upstream source: Transferred USDX and sUSDX from Arbitrum address 0x872757006b6F2Fd65244C0a2A5fdd1f70A7780f4;

stS from Sonic address 0x045371528A01071D6E5C934d42D641FD3cBE941c;

The transfers came from the Ethereum addresses 0xaa760d53541d8390074c61defeaba314675b8e3f and 0x506d1f9efe24f0d47853adca907eb8d89ae03207.

Transfer details: Assets were exchanged for ETH and WETH on Ethereum through platforms such as Velora, CowSwap, KyberSwap, and ODOS, and some assets were transferred across chains to Arbitrum and Sonic through LI.FI.

Exchange stS for S on Sonic using KyberSwap.

Balance status: Apart from transferring 7,000 ETH to the above address 0xaa760d53541d8390074c61defeaba314675b8e3f, no other funds have been transferred out.

The relevant addresses have been added to the SlowMist AML malicious address database, and we will continue to monitor any unusual fund movements.

On November 6, Balancer released an official statement, saying that although the attack had a wide impact, the rapid response from multiple parties significantly reduced the losses in a short period of time.

(https://x.com/Balancer/status/1986104426667401241)

The current funding progress is as follows:

  1. SEAL Whitehat Safe Harbor (BIP-726, Oct 2024): Thanks to the legal framework of SEAL Whitehat Safe Harbor (BIP-726) which came into effect in October 2024, the white hat team was able to intervene quickly and coordinate the handling of the incident.
  2. HyperNative's automated emergency pause mechanism was triggered: At 08:06 UTC, Hypernative's emergency pause system was activated; by 08:07 UTC, all CSPv6 pools on the affected network had been paused to prevent further spread.
  3. All CSPv6 liquidity pools that could be suspended have entered recovery mode, including low TVL liquidity pools that were not previously included in the statistics.
  4. CSPv6 Factory Functionality Disabled: New vulnerable pools cannot be created until the fix is complete.
  5. All incentives and emissions from the affected pools have been terminated in order to preserve BAL and partner reward assets.
  6. Major LPs have exited safely: including Crypto.com (approximately $800,000, cdcETH/wstETH) and Ether.fi (approximately $1,060,000, eBTC/wBTC).
  7. Stakewise has recovered 5,041 osETH (approximately US$19 million) and 13,495 osGNO (approximately US$1.7-2 million), representing about 73.5% of the stolen osETH. These assets will be returned to affected users proportionally.
  8. Berachain validator network paused: To control Balancer v2’s exposure on BEX, on-chain operations have been paused and an emergency fork has been initiated.
  9. Sonic Labs Freezes Related Addresses: Suspected attacker addresses associated with Beets (a Balancer v2 fork on Sonic) have been frozen to prevent further transfers or exchanges of funds.
  10. Base MEV robots assisted in the recovery: approximately $150,000 has been recovered.
  11. BitFinding white-hat team: Successfully intercepted and recovered approximately $600,000 in assets on the mainnet.
  12. Monerium has frozen approximately 1.3 million euros in assets to prevent further capital outflow.
  13. Gnosis Bridge Restrictions: In coordination with the Monerium team, cross-chain transfers on the Gnosis Chain are temporarily restricted to reduce the risk of cross-chain propagation.
  14. The SEAL team is communicating with the attackers: They are continuing negotiations on the return of funds in accordance with the SEAL framework.
  15. More white-hat teams are joining the support: multiple security teams, including SNP, are assisting with analysis, rescue, and fund recovery.

Currently, Balancer is actively collaborating with security partners, researchers, exchanges, and white-hat teams to facilitate the recovery of funds. A more detailed post-event analysis report will be released after verification and liquidation are completed.

Summarize

The core of this attack lies in the attacker's exploitation of a precision loss flaw in the Balancer v2 protocol's Composable Stable Pool implementation when performing integer fixed-point arithmetic on scaling factors. By carefully crafting small-amount exchanges, the attacker amplified the error caused by this flaw, allowing them to create enormous profits through bulk swaps. The SlowMist security team recommends that project teams and auditors strengthen their testing coverage for extreme scenarios and boundary conditions when facing similar situations, especially considering precision handling strategies in low-liquidity scenarios.

refer to

[1] https://docs-v2.balancer.fi/concepts/pools/composable-stable.html

[2] https://docs.balancer.fi/concepts/core-concepts/balancer-pool-tokens.html

[3] https://docs.balancer.fi/concepts/vault/token-scaling.html

[4] https://docs-v2.balancer.fi/reference/swaps/batch-swaps.html

[5] https://docs-v2.balancer.fi/concepts/advanced/valuing-bpt/valuing-bpt.html#informational-price-evaluation

Disclaimer: As a blockchain information platform, the articles published on this site represent only the personal views of the authors and guests and do not reflect the position of Web3Caff. The information contained in the articles is for reference only and does not constitute any investment advice or offer. Please comply with the relevant laws and regulations of your country or region.

Source
Disclaimer: The content above is only the author's opinion which does not represent any position of Followin, and is not intended as, and shall not be understood or construed as, investment advice from Followin.
Like
Add to Favorites
Comments