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
~$10.26M Lost: Term Finance, MAYAChain | BlockSec Weekly
Security Insights

~$10.26M Lost: Term Finance, MAYAChain | BlockSec Weekly

During the week of August 17-23, 2026, two notable security incidents resulted in approximately $10.26M in total losses across Ethereum and MAYAChain. The highlighted Term Finance incident (~$8.5M) was a flawed governance design rather than a coding bug: each vault ships its own on-chain DAO whose support-threshold and participation checks are purely relative, with no absolute floor; with almost no one taking part in governance, there was no electorate to vote a proposal down and no guardian to cancel one, so an attacker acquired a supermajority of a vault's voting power for roughly 0.5 ETH and, after the execution delay elapsed, drained six of Term's vaults for approximately $8.5M in total. MAYAChain (~$1.76M) lost funds to a chain of accounting and state-validation defects, where a single crafted deposit made valid withdrawals appear to have failed, triggered a recovery path that inflated a low-liquidity pool's recorded native-token balance with no real backing, and let the attacker drain the inflated value by adding and withdrawing liquidity.

Harmony Cross-Shard ONE Mint + ~$47M Key Losses | BlockSec Weekly
Security Insights

Harmony Cross-Shard ONE Mint + ~$47M Key Losses | BlockSec Weekly

During the week of August 10-16, 2026, 5 notable security incidents are featured, involving approximately $47M in quantified losses, with the detailed analysis focused on a chain-implementation flaw in the Harmony Layer-1. Harmony suffered unauthorized minting of native ONE through a cross-shard receipt replay: destination shards derived the receipt spent-marker from unauthenticated MerkleProof.ShardID and BlockNum fields instead of the signed source header, so an already-credited receipt could be replayed with no matching source-shard debit. Approximately 3.01T ONE was forged, but its nominal value far exceeds the token's market capitalization and is neither realizable nor confirmed realized loss, so Harmony is excluded from the total; the ~$47M came from private-key compromises (Unknown Whale Wallet ~$25M, Kite ~$14M, and Coinsbuy ~$7.9M) plus a Fox business-logic flaw (~$117K).

~$1.6M Lost: Moke Token, LpdFi Exploits | BlockSec Weekly
Security Insights

~$1.6M Lost: Moke Token, LpdFi Exploits | BlockSec Weekly

During the week of August 3-9, 2026, 2 notable security incidents on BNB Chain resulted in approximately $1.6M in total losses, both from price manipulation. The highlighted LpdFi incident (~$697K) reused the same manipulable PancakeSwap pair reserves for both order valuation and interest redemption, letting the attacker inflate a position's principal and reshape the pool to redeem an oversized interest claim. Moke Token (~$906K) combined a manipulable spot price with duplicated LP dividend accounting to claim inflated MOKE and collect the resulting BNB dividends multiple times.

Best Security Auditor for Web3

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

BlockSec Audit