Back to Blog

#3 Balancer V2 Incident: A Rounding Inconsistency Breaks the Invariant and Propagates Across Chains

Code Auditing
February 10, 2026

#3 Balancer V2 Incident: A Rounding Inconsistency Breaks the Invariant and Propagates Across Chains

On November 3, 2025, Balancer V2's Composable Stable Pools, along with several forked projects across multiple chains, suffered a coordinated exploit that resulted in total losses of over $125 million, with approximately $45 million reportedly recovered. The root cause was price manipulation enabled by precision loss in the invariant calculation, stemming from inconsistent rounding between the upscaling and downscaling operations, which ultimately distorted the BPT (Balancer Pool Token) pricing logic.

This incident stands out as one of the top ten security incidents of 2025 not only because of the scale of losses, but also due to the subtlety of the underlying bug. Moreover, the exploit quickly propagated across multiple chains and affected both Balancer and its forks, highlighting how shared codebases and composable DeFi infrastructure can significantly amplify systemic risk.

We have published an extensive report, "In-Depth Analysis: The Balancer V2 Exploit" [1], which provides a detailed technical breakdown. Below, we present a concise illustration of the incident.

Background

Balancer V2's Composable Stable Pool

The affected component in this attack was the Composable Stable Pool [2] of the Balancer V2 protocol. These pools are designed for assets that are expected to maintain near 1:1 parity (or trade at a known exchange rate) and allow large swaps with minimal price impact, thereby significantly improving capital efficiency between like-kind or correlated assets. Each pool has its own Balancer Pool Token (BPT), which represents the liquidity provider's share of the pool, along with the corresponding underlying assets.

  • This pool adopts Stable Math (based on Curve's StableSwap model), where the invariant D represents the pool's virtual total value.

  • The BPT price can be approximated as:

Price(BPT)DtotalSupplyPrice(BPT) \approx \frac{D}{totalSupply}

From the above formula, if D can be made smaller on paper (even without any actual loss of funds), the BPT price will appear cheaper.

batchSwap() and onSwap()

Balancer V2 provides the batchSwap() function, which enables multi-hop swaps within the Vault [3]. There are two swap types determined by a parameter passed to this function:

  • GIVEN_IN ("Given In"): the caller specifies the exact amount of the input token, and the pool calculates the corresponding output amount.
  • GIVEN_OUT ("Given Out"): the caller specifies the desired output amount, and the pool computes the required input amount.

Typically, a batchSwap() consists of multiple token-to-token swaps executed via the onSwap() function. This process inevitably involves amount calculations tied to the invariant D [1].

Scaling and Rounding

To normalize the calculations across different token balances, Balancer performs the following two operations:

  • Upscaling: Scale balances and amounts up to a unified internal precision before performing calculations.
  • Downscaling: Convert the results back to their native precision, applying directional rounding (for example, input amounts are usually rounded up to ensure the pool does not undercharge, while output amounts are often rounded down).

Upscaling and downscaling are theoretically paired operations: multiplication and division, respectively. However, an inconsistency exists in the implementation of these two operations. Specifically, the downscaling operation has two variants or directions: divUp and divDown. In contrast, the upscaling operation has only one direction, namely mulDown.

Vulnerability Analysis

The underlying issue arises from the rounding-down operation performed during upscaling in the BaseGeneralPool._swapGivenOut() function. In particular, _swapGivenOut() incorrectly rounds down swapRequest.amount through the _upscale() function. The resulting rounded value is subsequently used as amountOut when calculating amountIn via _onSwapGivenOut(). This behavior contradicts the standard practice that rounding should be applied in a manner that benefits the protocol.

Therefore, for a given pool (wstETH/rETH/cbETH), the computed amountIn underestimates the actual required input. This allows a user to exchange a smaller quantity of one underlying asset (e.g., wstETH) for another (e.g., cbETH), thereby decreasing the invariant D as a result of reduced effective liquidity. Consequently, the price of the corresponding BPT (wstETH/rETH/cbETH) becomes deflated, since BPT price = D / totalSupply.

Attack Analysis

The attacker executed a two-stage attack, likely to minimize detection risk:

  • In the first stage, the core exploit was performed within a single transaction, yielding no immediate profit.
  • In the second stage, the attacker realized profits by withdrawing assets in a separate transaction.

The first stage can be further divided into two phases: parameter calculation and batch swap. Below, we illustrate these phases using an example attack transaction (TX) on Arbitrum.

The Parameter Calculation Phase

In this phase, the attacker combined off-chain calculations with on-chain simulations to precisely tune each hop's parameters in the next (batch swap) phase, based on the current state of the Composable Stable Pool (including scaling factors, amplification coefficient, BPT rate, swap fees, and other parameters). The attacker also deployed an auxiliary contract to assist with these calculations, which may have been intended to reduce exposure to front-running. Please refer to [1] for more details.

The Batch Swap Phase

Then, the batchSwap() operation can be broken down into three steps:

Step 1: The attacker swaps BPT (wstETH/rETH/cbETH) for underlying assets to precisely adjust the balance of one token (cbETH) to the edge of a rounding boundary (amount = 9). This sets up the conditions for precision loss in the next step.

Step 2: The attacker then swaps between another underlying (wstETH) and cbETH using a crafted amount (= 8). Due to rounding down when scaling token amounts, the computed Δx becomes slightly smaller (8.918 to 8), leading to an underestimated Δy and thus a smaller invariant (D from Curve’s StableSwap model). Since BPT price = D / totalSupply, the BPT price becomes artificially deflated.

Step 3: The attacker reverse-swaps the underlying assets back into BPT, restoring balance while profiting from the deflated BPT price.

Summary

This incident involved a coordinated series of exploit transactions targeting Balancer V2's Composable Stable Pools and multiple forked deployments across different chains, resulting in substantial losses. After the first exploit, copycat transactions rapidly emerged, showing how quickly an attack pattern can propagate once exposed.

Key lessons:

  • Rounding & Precision Handling: Every scaling and precision operation on token amounts should round in the direction that benefits the protocol. A single inconsistency between _upscale() (round-down only) and the downscaling operations (directional rounding) was sufficient to create an exploitable pricing distortion.
  • Arms Race in Security: The attacker split manipulation and profit extraction across separate transactions to evade detection. Detection systems should correlate related transactions, not just flag individual ones.
  • Operational Security: Once the exploit pattern was public, copycats replicated it across chains within minutes. Protocols sharing a codebase need coordinated monitoring and rapid cross-chain pause capabilities.

Reference

  1. https://blocksec.com/blog/in-depth-analysis-the-balancer-v2-exploit

  2. https://docs-v2.balancer.fi/concepts/pools/composable-stable.html

  3. https://docs-v2.balancer.fi/reference/swaps/batch-swaps.html


About BlockSec

BlockSec is a full-stack blockchain security and crypto compliance provider. We build products and services that help customers to perform code audit (including smart contracts, blockchain and wallets), intercept attacks in real time, analyze incidents, trace illicit funds, and meet AML/CFT obligations, across the full lifecycle of protocols and platforms.

BlockSec has published multiple blockchain security papers in prestigious conferences, reported several zero-day attacks of DeFi applications, blocked multiple hacks to rescue more than 20 million dollars, and secured billions of cryptocurrencies.

Sign up for the latest updates
~$4.1M Lost: Taiko, SecondFi Exploits | BlockSec Weekly
Security Insights

~$4.1M Lost: Taiko, SecondFi Exploits | BlockSec Weekly

This weekly blockchain security report covers two notable incidents from June 22-28, 2026, with approximately $4.1M in confirmed losses across Ethereum and Cardano. The Taiko bridge exploit combined an exposed SGX enclave signing key with an incomplete attestation policy that failed to reject debug enclaves, allowing the attacker to register a malicious prover and forge L2 state proofs on Ethereum. The SecondFi wallet vulnerability stemmed from a cryptographic implementation flaw in Ed25519 nonce derivation that removed the secret input, enabling offline private key recovery from public Cardano transaction data.

~$18M Lost: jaredFromSubway, Aztec & More | BlockSec Weekly
Security Insights

~$18M Lost: jaredFromSubway, Aztec & More | BlockSec Weekly

This weekly blockchain security report covers June 15 to June 21, 2026, with 3 notable incidents across Ethereum and BNB Chain totaling approximately $18.3M in losses. Two incidents are analyzed in detail. Based on on-chain analysis, the highlighted jaredFromSubway incident reveals a reversed approval attack pattern: unlike traditional exploits where attackers abuse vulnerabilities in trusted DeFi contracts to drain user-approved assets, this MEV bot proactively approved its own assets to untrusted third-party contracts for arbitrage. The attacker constructed fake wrapper tokens and swap pools that emitted real events but never consumed the granted allowances, with reported total losses of ~$15M. The report also covers Aztec's second exploit in three days, where a missing equality constraint between two witnesses for `old_data_root` in the escape hatch ZK circuit allowed the attacker to prove ownership of fabricated notes against a fake Merkle tree while passing on-chain root validation.

Web3 Companion: The Open-Source Secure Agentic Wallet

Web3 Companion: The Open-Source Secure Agentic Wallet

BlockSec open-sources Web3 Companion, a security-first agentic wallet that treats its own AI agent as untrusted and uses key isolation, hard policies, and Passkey to protect on-chain assets.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit