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
~$1.35M Lost: BarnBridge, DeFiTuna | BlockSec Weekly
Security Insights

~$1.35M Lost: BarnBridge, DeFiTuna | BlockSec Weekly

This weekly report covers 2 security incidents from July 13 to July 19, 2026, with approximately $1.35M in total losses on Ethereum and Solana. DeFiTuna, a Solana lending protocol, lost ~$570K because the position health check treated a zero-value position as healthy regardless of outstanding debt; the attacker used controlled swap routing and a separate low-liquidity pool to trigger this defect. BarnBridge lost ~$776K after an attacker exploited the protocol's deprecated but still-active governance system on Ethereum to pass a malicious proposal and drain user-approved USDC.

~$800K Lost: Hinkal Double-Spend | BlockSec Weekly
Security Insights

~$800K Lost: Hinkal Double-Spend | BlockSec Weekly

This weekly security report covers 1 notable incident from June 29 to July 5, 2026, with approximately $800K in total losses on Ethereum. The Hinkal shielded-pool protocol was drained through a double-spend attack that likely exploited a flaw in the legacy note format, allowing the attacker to derive multiple nullifiers from a single deposit. The report analyzes the probable circuit-level vulnerability, the attack flow, and broader implications for nullifier-based privacy protocols.

Newsletter - June 2026
Security Insights

Newsletter - June 2026

This monthly report covers the three largest security incidents in June 2026, totaling approximately $22M in confirmed losses. A sophisticated honeypot attack drained ~$15M from JaredFromSubway's MEV bot by exploiting unchecked token allowances. Two legacy Aztec rollup deployments lost ~$4.35M through proof-settlement boundary gaps. SecondFi's Ed25519 implementation flaw exposed wallet private keys, resulting in ~$2.4M drained from 374 wallets. All three incidents share a common pattern: security guarantees that appeared intact on the surface but were never actually enforced.

Best Security Auditor for Web3

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

BlockSec Audit