StrataxOracle.getPrice() calls latestRoundData() but only validates answer > 0. The updatedAt and answeredInRound fields are discarded, so stale prices from oracle downtime or L2 sequencer issues flow into calculateOpenParams(), _executeUnwindOperation(), and calculateUnwindParams(), corrupting every position calculation.
At line 70, getPrice() discards all freshness data:
Chainlink feeds return stale data during network congestion, oracle heartbeat delays, or L2 sequencer downtime. Without a staleness check, getPrice() returns the last successful answer regardless of age.
A stale price that is higher than real market price causes calculateOpenParams() to overvalue collateral. Users borrow more than their collateral supports. When the oracle updates to the real price, the position's health factor drops below 1.0 and gets liquidated.
A stale price that is lower than real market price causes _executeUnwindOperation() to over-withdraw collateral, and calculateUnwindParams() to mislead users about their position state.
Likelihood: High — Chainlink delayed updates occur during network congestion. L2 sequencer downtime has affected Arbitrum and Optimism multiple times. No special conditions needed.
Impact: High — A 3x leveraged position with a stale price 33% above reality over-borrows by ~50%. The user loses their entire collateral deposit when the oracle updates and the position is liquidated.
Place in test/exploits/Exploit_StaleOracle.t.sol. Run: forge test --match-contract Exploit_StaleOracle -vv
Validate freshness and round completeness before accepting the price. The 3600s threshold matches Chainlink's ETH/USD heartbeat:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.