# Oracle provider switch state corruption

Provider swaps that regress version, deadlock on uncommitted requests, or settle empty versions

_Area: DeFi oracles, liquidations and flash loans. Seen in 3 disclosed reports; latest 2023-07-17. Updated 2026-10-25._

## How it works
Swapping an oracle provider is treated as a simple pointer change, but downstream settlement assumes the version stream is monotonic and complete. Three assumptions break: (1) the new provider's latest version is newer than the old one's; (2) the old provider's last request can always be committed; (3) global and local position state settle against the same version. When any fails, positions settle against empty or mismatched versions, producing PnL that does not match real collateral.

## Where it shows up
- `Oracle.update(newProvider)` with no check that `newProvider.latest().timestamp > oldProvider.latest().timestamp` [E3](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-9.md)
- Switch gated on "previous provider's last request committed" where the commit path has time-bounded validation (e.g. price must fall in a window around request time) [E2](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-3.md)
- Settlement loops that invalidate positions to a previous latest, then a later sync step advances latest to a valid version [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-2.md)
- `_processPositionLocal` reading a version that was never stored (empty/zero values) [E3](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-9.md)
- Global and local settlement paths that can pick different next-valid versions for the same event [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-2.md)

## How to review
Check the invariant: after any provider switch, `latestVersion` is strictly greater than before, and every position settles against a version that actually exists with real values. Verify the switch cannot be gated on an item that is permanently uncommittable (time-bounded commit vs. unbounded wait). Confirm global and local settlement derive the same next-valid version from the same event; any asymmetry in which version each side anchors to is a bug. Trace what happens when `nextPosition.timestamp` has no stored version.

## Variants seen
- Version regression: new provider's latest is older, so settlement uses an empty version and mis-accounts collateral [E3](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-9.md)
- Deadlock: last request of old provider can never be committed, freezing all price updates with no recovery path [E2](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-3.md)
- Desync: invalid versions invalidated to previous latest, but global and local settle against different next-valid versions, so PnL accrues over different states [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-2.md)

## Impact and severity
High: total user collateral can exceed deposited funds, protocol cannot pay back all users [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-2.md); market bricked with no price updates and no fix [E2](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-3.md); wrong settlement against non-existent versions [E3](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-9.md). Severity rises when the switch is one-way or the deadlock has no admin escape, and when accounting errors compound across many positions before detection.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-2.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-3.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-9.md
