Full Report
The article begins with a blurb on how to and how NOT to run a good bug bounty program. The first issue is NOT following up with emails from whitehats. Second is paying less than the advertised bounty or it being too small in the first place. The second point is a major issue. If the bounty is 1K and the funds at risk is 1B, the incentive to steal far outweighs the reward; this makes it more likely that a vulnerability found will be exploited. Apparently, Balancer had advertised 2M but only paid of 25% on a previous bug. Balancer is an AMM in the DeFi space. It allows a pool containing two or more tokens to swap between them, while the people providers liquidity get some proceed of the fees for performing the swaps. This is all very standard functionality for an AMM though. MerkleRedeem's purpose is to distribute rewards. The original way this was architected only allowed for a single token per contract. This led the way for the Merkle Orchard contract, which allows for multiple tokens being claimable in a single contract. All rewards were in this contract. The code for submitting a reward claim took in an array of ids. The program would iterate on these ids and send the user all of the tokens they deserved. At the end of the loop, it would mark the id as used, meaning it couldn't be claimed more than once. The vulnerability is that the continue iterating through the list and ONLY at the end mark the id as used. This allowed for the same claim to be made several times, effectively creating an infinite claiming glitch. In total, between several chains, 3.2M of tokens could have been stolen. It should be noted that this was reported by the author of this post. They made 50ETH on an out of scope target, which is pretty cool. This code had made it past four security audits, which is pretty crazy. Immunefi created an article with this as well.
Analysis Summary
# Vulnerability: Balancer Merkle Orchard Multi-Token Claim Loophole
## CVE Details
- **CVE ID:** N/A (DeFi/Smart Contract vulnerabilities often lack formal CVE assignments)
- **CVSS Score:** Estimated 9.1 (Critical)
- **CWE:** CWE-670: Always-Incorrect Control Flow Implementation; CWE-691: Insufficient Control Flow Management
## Affected Systems
- **Products:** Balancer Protocol (Automated Market Maker)
- **Versions:** Merkle Orchard Contract
- **Configurations:** Deployments on multiple chains (including Ethereum Mainnet, Polygon, and Arbitrum) utilizing the multi-token reward distribution architecture.
## Vulnerability Description
The vulnerability resided in the logic of the `claimRewards` function within the **Merkle Orchard** contract. This contract was designed to allow users to claim rewards for multiple tokens in a single transaction by passing an array of `Claim` identifiers.
The technical flaw was an incorrect loop implementation:
1. The program iterated through an array of claim IDs provided by the user.
2. For each ID, the contract verified the Merkle proof and transferred the tokens to the user.
3. **The Critical Error:** The contract only marked the claim ID as "claimed" (used) *after* the entire loop finished iterating.
Because the state update (marking the ID as used) occurred outside and after the processing loop rather than inside it, a malicious actor could pass the same valid claim ID multiple times within a single array. The contract would verify the same proof repeatedly in one transaction, sending tokens for every instance of the ID in the array, effectively allowing an "infinite" claim of available contract funds.
## Exploitation
- **Status:** Not exploited in the wild (Disclosed via Bug Bounty program by researcher *riptide*).
- **Complexity:** Low (Requires only a single valid Merkle proof and a crafted array).
- **Attack Vector:** Network (Smart Contract Interaction).
## Impact
- **Confidentiality:** None
- **Integrity:** High (Unauthorized manipulation of token balances)
- **Availability:** High (Loss of all reward funds held in the contract)
- **Total Risk:** Over $3.2M USD in various tokens were at risk across multiple chains.
## Remediation
### Patches
- The Balancer team deployed updated versions of the Merkle Orchard contracts.
- The fix involves moving the state update (marking the `distributionIndex` as claimed) inside the loop, immediately after the transfer, or utilizing a "Checks-Effects-Interactions" pattern to prevent multiple processing of the same ID.
### Workarounds
- At the time of discovery, the primary mitigation was the rapid migration of funds to a secure, patched contract.
## Detection
- **Indicators of Compromise:** Multiple transfers of the same token amount to the same address within a single `claimRewards` transaction hash.
- **Detection Methods:** Static analysis of loop structures in smart contracts to ensure state changes (nullifying the "ticket") occur before or immediately during the iteration of each element, rather than at the end of the batch.
## References
- **Original Research:** hxxps[://]paragraph[.]com/@riptide/balancer-s-bountiful-merkle-orchard
- **Immunefi Case Study:** hxxps[://]medium[.]com/immunefi/balancer-merkle-orchard-double-entry-bug-fix-post-mortem-d335359cd91e
- **Balancer Protocol:** hxxps[://]balancer[.]fi/