# Signed price replay and stale oracle reports

Signed price payloads accepted without strict monotonic timestamp or index-uniqueness checks, allowing replay of older observations.

_Area: DeFi oracles, liquidations and flash loans. Seen in 8 disclosed reports; latest 2026-09-16. Updated 2026-10-23._

## How it works
A price is delivered as a payload signed by a trusted party (DON, keeper, Muon, Tellor). The contract verifies the signature and trusts the number. The broken assumption: "valid signature" means "current price." A signature only proves the signer once attested that value at some time. If the consumer does not enforce that the payload's timestamp/round is strictly newer than what it already stored, any still-valid older payload can be re-submitted and overwrite the newer price. The attacker picks the observation that favors them.

## Where it shows up
- Permissionless `verifyReport`/`updatePrice`/`commit` entrypoints that forward to a verifier and store the result [E1](https://bugbountylibrary.com/r/dhl%3A20260916-primefinance.md)[E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md).
- A validity window (e.g. 3 minutes) checked without a monotonicity or cooldown check [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md).
- Two entrypoints writing the same oracle state where only one enforces ordering [E4](https://bugbountylibrary.com/r/sherlock%3A2023-09-perennial%3AM-2.md)[E5](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md).
- Signature schemes committing to caller-supplied array indexes [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AM-34.md).
- Integrations where disputes/removals roll the feed back to older values [E6](https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AM-10.md).
- Timestamp checks with only an upper bound, no lower bound [E7](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-1.md).

## How to review
The invariant: for each feed, the stored price must come from a payload whose timestamp/round is strictly greater than the last consumed one, and the consumer must persist that last-consumed value. Check every write path, not just the primary one. For index-based signatures, verify indexes are unique and form a valid permutation. For time-bounded payloads, check both bounds against on-chain event time. For Tellor-style feeds, track last consumed timestamp per queryId and reject non-newer values.

## Variants seen
- Stale DON report overwrites stored price ~52x [E1](https://bugbountylibrary.com/r/dhl%3A20260916-primefinance.md).
- Replay within validity window warps price back and forth atomically [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md).
- Duplicate price indexes let one signature validate a different slot [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AM-34.md).
- Front-run `commit()` consumes the monotonicity slot, griefing `commitRequested()` [E4](https://bugbountylibrary.com/r/sherlock%3A2023-09-perennial%3AM-2.md).
- Permissionless `commit()` skips the publish-time check the primary path enforces [E5](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md).
- Disputed Tellor value removed, older value resurfaces [E6](https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AM-10.md).
- Only upper time bound enforced, old signed price replayed to force liquidation [E7](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-1.md).

## Impact and severity
Inflated collateral and drained lending pools [E1](https://bugbountylibrary.com/r/dhl%3A20260916-primefinance.md); manipulated trades and unfair liquidations [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md)[E5](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md)[E7](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-1.md); protocol fund loss [E5](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md); mispriced vault NAV and withdrawals [E6](https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AM-10.md). Severity is high where the attacker can borrow or liquidate against the warped price. Worse when the entrypoint is permissionless and the payload stays valid for a window, giving repeated atomic manipulation.

## Why fixes fail
Fixing only the primary path leaves the permissionless fallback unprotected [E5](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md). Adding a freshness window without monotonic ordering still allows replay of older-but-valid payloads [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md). Checking only one timestamp bound leaves the other open [E7](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-1.md).

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20260916-primefinance.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-08-sentiment-v2%3AH-1.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AM-34.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2023-09-perennial%3AM-2.md
- E5: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-2.md
- E6: https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AM-10.md
- E7: https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-1.md
