# Missing circuit breaker checks in ethPerCvx() for Chainlink's price feed

ethPerCvx() lacks Chainlink min/max circuit-breaker checks, so a CVX flash crash returns minAnswer and lets an attacker mint excessive afEth via deposit().

- Payout: Contest reward
- Severity: medium
- Program: Asymmetry Finance
- Credited: MiloTruck
- Disclosed: 2024-02-06
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-09-asymmetry-findings/issues/31
- Library page: https://bugbountylibrary.com/r/c4%3A2023-09-asymmetry%3AM-09
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** VotiumStrategyCore.ethPerCvx() Chainlink CVX/ETH price feed
**Root cause:** ethPerCvx() validates roundId, answer>=0 and staleness but never bounds answer against minAnswer/maxAnswer, so during a flash crash the feed returns the clamped minAnswer instead of the real price.
**Steps:**
1. Observe ethPerCvx() only checks `cl.answer >= 0`, `updatedAt != 0`, and `block.timestamp - updatedAt <= 25 hours`.
2. Confirm CVX/ETH AccessControlledOffchainAggregator has minAnswer=1e13, maxAnswer=1e18.
3. Assume CVX flash-crashes below 1e13; feed returns 1e13.
4. Call `deposit()` with 10 ETH; vStrategy.price() = cvxPerVotium()*1e13/1e18 = 1e13.
5. totalValue = (5e18*1e18)+(5e34*1e13) ≈ 5e47; amountToMint = totalValue/priceBeforeDeposit ≈ 1e30 afEth.
6. Attacker now holds majority of afEth supply and withdraws most of TVL.
**How found:** Code review of ethPerCvx() validation logic; noticed absence of min/max bounds and cross-referenced the on-chain aggregator's minAnswer/maxAnswer, then traced price() into AfEth.deposit() mint math.
**Exploitation:** Attacker waits for or triggers a CVX flash crash so the Chainlink feed clamps to minAnswer, then calls deposit() to mint a disproportionate amount of afEth, then redeems to drain protocol TVL at the expense of prior depositors.
**Insight:** When auditing oracle consumers, check not just staleness/roundId but whether the answer is bounded against the aggregator's minAnswer/maxAnswer; a clamped feed during a crash silently returns a wrong-but-valid price that flows into share minting.
