Full Report
Balancer V2 is a key lending and borrowing protocol with lots of interesting functionality. Within V2, arbitrary contract is capable of being a vault; this is to maximize innovation and flexibility. The batchSwap() function can be used to perform multiple swaps atomically to get the best path. This also contains a flash swap by only having to pay for the funds at the end. Balancer was trying to be as capital efficient as possible. In a pool, the ratio is what calculates the price of the token. To have stability, lots of tokens are required; this ends up with a large amount of idle tokens that are doing nothing useful. They tried a few different things to fix this but settled on linear/boosted pools. Lending protocols have an underlying token in exchange for the platform/LP token, such as aTokens on Aave. From this, users earn yield for liquidity. Since these are always rebasing, a wrapped version of these tokens in a Balancer vault is used. To prevent the constant wrapping and unwrapping of assets, they created linear pools. Within a linear pool, there is a third token: the Balancer Pool Token (BPT). Pools that contain tokens that are also pools themselves are called composable or recursive. What's cool about this is that the BPT can be swapped like any other token in the pool itself. Now, for the vulnerability! The issue existed in the common library ScalingHelpers. In DeFi security, the rounding direction is critical to get right for security. Any rounding errors should always favor the pool. To be efficient, they decided to always round down and expect that the consequence would be minimal. This was true for everything except linear pools. A bunch of crazy things coming together made the rounding error significant: Linear pools have zero fees when balanced and no minimum balances. Initialized with pre-minted BPT, creating a near infinite supply. This is available for flash swap operations. Why is this significant? The batch swaps settle at the end. Individual swaps perform calculations on scaled balances - including rates - which depend on the intermediate pool state. Since this doesn't work based upon the vaults pool balances, the math is deeply effected. There is a quick and dirty attack path: Borrow BPT via a flash swap with the rate slightly greater than 1 and trade it for main and wrapped to reduce the token balances to near zero. Craft a trade that exploits the rounding error from above to make the total balance equal the virtual supply. This will result the rate to 1. Repay the flash swap at a new lower rate for a profit. This can also be done on the main and wrapped tokens as well. This is where the story gets wild. While trying to get people to take the funds out of the paused and effected pools, a different vulnerability was found! The exploit from before dropped the rate; they found a rounding error to increase the rate. This exploits some decimal precision and rounding issues described above. When the rate is high, the BPT trades at a premium within the Composable Stable pool. Raising the rate was fine because they couldn't get the rate back to profit from it; this was discussed during the design. However, the attacker found a way to drop the rate back down. During the initialization stage of a pool, the check is that the total supply is zero. By using the methods from above, this condition is possible to hit, recreating the initialization scenario. With this, the attacker could profit from the attack. Trying to mitigate this was interesting: it's tough being a "fully decentralized" protocol. You want to be able to shut stuff off but you shouldn't be able to with fully decentralizion. Some items had a pause function, some were upgradable and a recovery mode. But, these weren't implemented in everything. At the end of the article, the author reflects on many things. First, they had several audits done and this bug lurked for over 2 years without getting discovered by a whitehat. The complexity of the protocol became too much. In particular, the bootstrapping of functionality over and over again in strange ways. Overall, a fascinating postmortem about an immensely important protocol.
Analysis Summary
# Vulnerability: Precision Loss and Rate Manipulation in Balancer Linear Pools
## CVE Details
- **CVE ID**: N/A (DeFi vulnerabilities often lack formal CVE assignments; identified by Balancer as the "August 2023 Boosted Pool Vulnerability")
- **CVSS Score**: 9.1 (Calculated estimate based on Critical severity)
- **CWE**: CWE-682: Incorrect Calculation; CWE-190: Integer Overflow or Wraparound (Rounding errors)
## Affected Systems
- **Products**: Balancer V2 Protocol
- **Versions**: V2 Vault deployments prior to August 2023.
- **Configurations**: Specifically "Boosted Pools" containing nested **Linear Pools** (e.g., Aave Linear Pools, ERC4626 Linear Pools) and **Composable Stable Pools**.
## Vulnerability Description
The vulnerability stems from a rounding error in the `ScalingHelpers` library used by Linear Pools. In Balancer V2, mathematical operations are generally designed to "round down" to favor the protocol's liquidity providers. However, in the context of Linear Pools—which utilize pre-minted Balancer Pool Tokens (BPT) and have no swap fees when balanced—this "always round down" logic created a significant discrepancy.
The flaw allows an attacker to manipulate the "rate" (the exchange value between the BPT and the underlying tokens). Because the math depends on intermediate pool states during a `batchSwap()`, an attacker can execute trades that exploit precision loss to force the virtual supply to equal the total balance. This resets the pool's rate logic, allowing an attacker to manipulate the price of BPT, profit from the resulting arbitrage, or re-initialize a pool to a state where they can drain assets.
## Exploitation
- **Status**: **Exploited in the wild** (Commenced August 27, 2023).
- **Complexity**: High (Requires multi-step flash swaps, complex math tailoring for specific pool states, and manipulation of decimal precision).
- **Attack Vector**: Network (Smart Contract Interaction via Ethereum/compatible chains).
## Impact
- **Confidentiality**: Low (Transaction data remains public).
- **Integrity**: Critical (Attackers can manipulate internal price rates and session states).
- **Availability**: Critical (Resulted in the depletion of funds in several pools; necessitated the permanent pausing of affected pools).
## Remediation
### Patches
- **Composable Stable Pool v5+**: A new version of the Composable Stable Pool was released in July 2023 to address initial rate provider concerns.
- **Linear Pool Updates**: Structural changes to how scaling and rounding are handled in constituent pools were implemented in subsequent versions.
### Workarounds
- **Emergency Pause**: The Emergency SubDAO triggered pause functionality for all pools where the feature was available.
- **Recovery Mode**: Affected pools were placed into "Recovery Mode" to allow LPs to withdraw funds at a proportional rate without further trading.
- **User Withdrawal**: Users were urged to migrate liquidity or withdraw immediately via the Balancer UI.
## Detection
- **Indicators of Compromise**:
- Large Flash Swaps involving BPT.
- Sequences of trades that leave pool balances near zero followed by a "rate reset" to 1.0.
- Transaction patterns involving the `batchSwap` function targeting linear/boosted pools.
- **Detection methods**: Balancer monitoring systems caught the August 27th exploit via real-time logic checks on pool invariants.
## References
- Balancer Forum Advisory: [https://forum.balancer.fi/t/vulnerability-found-in-some-pools/5102]
- Balancer Technical Postmortem: [https://medium.com/@juani_72357/rate-manipulation-in-balancer-boosted-pools-technical-postmortem-53db4b642492]
- Immunefi Bug Bounty Program: [https://immunefi.com/bounty/balancer/]