# Attacker can take advantage of Chainlink price not occuring within it's 60 minute heartbeat to make PriceAggregator calls fail

When Chainlink BTC/ETH price is stale (>60min), CoreSaltyFeed's raw pool reserves can be skewed by a swap, making PriceAggregator revert on price requests.

- Payout: Contest reward
- Severity: medium
- Program: Salty.IO
- Credited: israeladelaja
- Disclosed: 2024-04-19
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-01-salty-findings/issues/486
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-15
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:dos vuln:oracle-manipulation

**Target:** PriceAggregator / CoreChainlinkFeed / CoreSaltyFeed price oracle
**Root cause:** CoreChainlinkFeed returns 0 when the Chainlink answer is older than the 60-minute heartbeat, leaving PriceAggregator to rely on CoreSaltyFeed, which derives price from manipulable spot pool reserves rather than a TWAP.
**Steps:**
1. Deploy Salty.IO; mock Chainlink aggregator returning stale/zero latestRoundData so CoreChainlinkFeed yields price 0.
2. Seed WBTC/USDS and WETH/USDS pools with liquidity.
3. Attacker swaps WBTC->USDS (`pools.depositSwapWithdraw(wbtc, usds, 0.5e8, 0, block.timestamp)`) to skew reserves.
4. Attacker swaps WETH->USDS (`pools.depositSwapWithdraw(weth, usds, 5e18, 0, block.timestamp)`) to skew reserves.
5. Call `priceAggregator.getPriceBTC()` / `getPriceETH()`; both revert because the two non-zero feeds deviate beyond the allowed threshold.
**How found:** Code review of CoreChainlinkFeed's heartbeat check returning 0 and CoreSaltyFeed's use of raw pool reserves; recognized that with only two remaining feeds, a reserve skew exceeding the deviation threshold forces PriceAggregator to revert.
**Exploitation:** Attacker (optionally with flash-loaned capital) swaps into the WBTC/USDS and WETH/USDS pools during a Chainlink heartbeat lapse, skewing CoreSaltyFeed's reserve-derived price far from the Uniswap V3 TWAP; PriceAggregator then reverts on any price query, breaking protocol functionality that depends on it.
**Insight:** When an oracle aggregator tolerates one feed returning 0, the remaining feeds' manipulation resistance becomes the whole system's; spot-reserve feeds are trivially skewable, so a single stale-heartbeat window converts a benign fallback into a DoS lever.
