# `BalancerPairOracle` can be manipulated using read-only reentrancy

BalancerPairOracle.getPrice reads Balancer pool balances and BPT supply without checking the Vault reentrancy guard, letting an attacker desync them and force premature liquidations.

- Payout: Contest reward
- Severity: high
- Program: Blueberry
- Credited: cuthalion0x
- Disclosed: 2023-04-07
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2023-04-blueberry-judging/issues/141
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-04-blueberry%3AH-13
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:chained vuln:liquidation vuln:oracle-manipulation vuln:reentrancy

**Target:** BalancerPairOracle.getPrice / BlueBerryBank.liquidate
**Root cause:** getPrice computes f(balances)/pool.totalSupply() via external calls to BalancerVault.getPoolTokens and BalancerPool.getTotalSupply without verifying the Balancer Vault's reentrancy guard, so balances and supply can be read out of sync during a reentrant callback.
**Steps:**
1. Attacker takes a flash loan of tokens.
2. Call BalancerVault.joinPool() with borrowed tokens plus ETH; the Vault refunds excess ETH to the attacker contract, triggering receive().
3. Inside receive(), BPT supply is already updated but token balances are not.
4. Reenter BlueBerryBank.liquidate() on a victim position using the same Balancer pool as collateral.
5. liquidate() calls BalancerPairOracle.getPrice(), which reads stale balances via getPoolTokens() and inflated totalSupply(), yielding a deflated price.
6. Victim position is liquidated under false pretenses.
**How found:** Recognized that getPrice divides f(balances) by pool.totalSupply(), two data points that Balancer's read-only reentrancy can desync, and that the oracle never checks the Vault reentrancy guard.
**Exploitation:** Flash-loan capital, join a Balancer pool to trigger the ETH-refund callback, and within that callback call BlueBerryBank.liquidate() so the oracle reads desynced balances/supply and liquidates a healthy position.
**Insight:** Any oracle or integration reading Balancer pool balances and BPT supply as separate external calls is exploitable via the ETH-refund callback in joinPool; check the Vault's reentrancy guard (or a read-only equivalent) before trusting pool data.
