# Stale state after transitions

Old flags, mappings or fee fields left live after a transition, letting finished flows reopen or mix state

_Area: DeFi accounting and math bugs. Seen in 50 disclosed reports; 2 confirmed bounties: $10,000 and $1,000,000; latest 2025-08-27. Updated 2026-10-23._

## How it works
A transition is supposed to invalidate what the previous phase owned. It breaks when state is never cleared (a setter adds a new entry but leaves the old one live), never set (a guard or sentinel is missing so a flow can be re-entered), overwritten (a mutable field outside the storage key is rewritten to a favorable value), or cleared in the wrong place. Later code reads the leftover value as current. The broken assumption: that writing new state implicitly clears the old, that a guard checked earlier still reflects reality, or that a field can only be written once.

## Where it shows up
- Setters that add an entry to a shared accounting array without deleting the superseded one [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-notional-double-counting-free-collateral-bugfix-review.md).
- Lifecycle functions (reclaim, reset) callable after the flow executed, with params left in place [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md).
- State keyed by a recreatable identifier (e.g. an ERC-721 address) rather than the token instance [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md).
- Per-call fee fields reused across retries without being zeroed [E3](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-11.md).
- A mutable field driving an economic penalty that is not part of the storage key, so it can be overwritten [E6](https://bugbountylibrary.com/r/cantina%3Aprimev_oct2024%3A3.1.5.md).
- A zero-value field used as an "uninitialized" sentinel that a no-op path writes anyway [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10.md).
- A guard that reads cached eligibility before the call that refreshes it [E8](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md).
- A transition that freezes one contract but not a dependent module that keeps accruing or minting [E4](https://bugbountylibrary.com/r/h1%3A672664.md).
- A payout that reads config (denom, price) from mutable state whose setter guard ignores unsettled obligations [E5](https://bugbountylibrary.com/r/c4%3A2024-10-coded-estate%3AH-07.md).

## How to review
For each transition, list every piece of state the old phase owned and confirm it is explicitly cleared, set, or made unreachable. Invariant: after a transition, no read path can observe state belonging to a prior phase, and no field can be rewritten to change an already-decided outcome. Checklist:
- Setters that add an entry also delete the superseded one [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-notional-double-counting-free-collateral-bugfix-review.md).
- Reclaim/reset paths are gated on the flow not having executed [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md).
- Keys use the token instance, not a recreatable address [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md).
- Fee fields are zeroed after consumption, including across retries [E3](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-11.md).
- Penalty-driving fields are in the key or bounded against the window end [E6](https://bugbountylibrary.com/r/cantina%3Aprimev_oct2024%3A3.1.5.md).
- Sentinel fields are written only on real initialization [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10.md).
- Guards run after, not before, the refresh that updates their input [E8](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md).
- Enumerate every contract that can mint or accrue value and confirm each is frozen at shutdown [E4](https://bugbountylibrary.com/r/h1%3A672664.md).
- Setters for payout config check for pending obligations, not just time [E5](https://bugbountylibrary.com/r/c4%3A2024-10-coded-estate%3AH-07.md).

Distinguish from stale-cache/TOCTOU: here the stale value is never refreshed at all.

## Variants seen
- Prior active currency not cleared on bitmap change, double-counted collateral [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-notional-double-counting-free-collateral-bugfix-review.md).
- Stale shutdown params keyed by ERC-721 address, reopened after completion [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md).
- Gas fee field reused across retries, draining reserves [E3](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-11.md).
- Shutdown cages vat but not pot, DSR keeps minting after rate fixed [E4](https://bugbountylibrary.com/r/h1%3A672664.md).
- Mutable denom swapped before finalization, draining pooled deposits [E5](https://bugbountylibrary.com/r/c4%3A2024-10-coded-estate%3AH-07.md).
- Overwritable dispatchTimestamp bypasses bid decay [E6](https://bugbountylibrary.com/r/cantina%3Aprimev_oct2024%3A3.1.5.md).
- Sentinel timestamp pre-set by unauthenticated caller, locking rewards [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10.md).
- Eligibility guard reads stale price before refresh, disqualified users claim [E8](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md).

## Impact and severity
High: full liquidity drain [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-notional-double-counting-free-collateral-bugfix-review.md)[E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md), theft of accumulated fees [E3](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-11.md), collateral theft after shutdown [E4](https://bugbountylibrary.com/r/h1%3A672664.md), pooled deposit theft [E5](https://bugbountylibrary.com/r/c4%3A2024-10-coded-estate%3AH-07.md), bypassed slashing [E6](https://bugbountylibrary.com/r/cantina%3Aprimev_oct2024%3A3.1.5.md), permanently locked rewards [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10.md), emissions paid to ineligible users [E8](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md). Worse when no reset/cancel path exists [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md) or a single uncaged minter survives the freeze [E4](https://bugbountylibrary.com/r/h1%3A672664.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-notional-double-counting-free-collateral-bugfix-review.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-5.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-11.md
- E4: https://bugbountylibrary.com/r/h1%3A672664.md
- E5: https://bugbountylibrary.com/r/c4%3A2024-10-coded-estate%3AH-07.md
- E6: https://bugbountylibrary.com/r/cantina%3Aprimev_oct2024%3A3.1.5.md
- E7: https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10.md
- E8: https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md
