# Balancer oracle deadlock from cumulative price weight

BalancerPriceOracle.updatePrice() deadlocks permanently once cumulativePrice grows large, since slippage check against stale average rejects any market move beyond maxSlippage.

- Payout: Contest reward
- Severity: medium
- Program: Olas
- Credited: Valves
- Disclosed: 2026-05-18
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2026-01-olas#m-12
- Library page: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-12
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:dos vuln:oracle-manipulation

**Target:** BalancerPriceOracle.sol updatePrice/validatePrice TWAP oracle
**Root cause:** Slippage validation runs against the stale average price before state update, and cumulativePrice accumulates unbounded historical time weight, making the average inertial and unable to track market moves beyond maxSlippage.
**Steps:**
1. Oracle runs at stable price 1e18 for 365 days: cumulativePrice = 1e18 * 31_536_000 = 3.1536e25, averagePrice = 1e18.
2. Market moves 10% to 1.1e18; elapsedTime = 315_360_000s.
3. updatePrice computes upperBound = 1e18 * 1.05 = 1.05e18; currentPrice 1.1e18 exceeds it.
4. Slippage check fails, function returns false, state (cumulativePrice, averagePrice) never updates.
5. Frozen cumulative weight dominates any future elapsedTime, so average cannot catch up; validatePrice keeps rejecting valid prices and accepting stale ones.
**How found:** Code reading of the TWAP formula and slippage check ordering; noticed cumulativePrice/snapshot.averagePrice grows unbounded and dominates the denominator, then modeled a numeric example showing rejection after a 10% move.
**Exploitation:** No direct theft; the oracle permanently returns false, blocking any protocol action (buybacks, exits) that depends on validatePrice, and validatePrice returns inaccurate results.
**Insight:** In TWAP oracles, check whether the cumulative accumulator is bounded or windowed; an unbounded cumulativePrice divided by averagePrice acts as an ever-growing weight that makes the average unable to track real price moves, and validating slippage against the pre-update average turns that into a permanent DoS.
