# Append-only state with no removal path

Monotonic counters or headers that gate progress but have no reachable delete, rollback, or release path

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2025-10-21. Updated 2026-10-24._

## How it works
A state machine tracks outstanding items (headers, packet commitments, reserved slots) and only advances when that count reaches zero or the next value is exactly latest+1. The assumption that breaks: the code assumes every item will eventually resolve or be removed. If the only removal path is unreachable, conditional, or controlled by an external party, the counter never drains and progress halts permanently. The invariant "every increment has a reachable decrement on all paths" is violated.

## Where it shows up
- Strict monotonic checks like `height == latest + 1` with no overwrite/delete branch.
- A `Remove*`/`Delete*` keeper or function that exists but is never wired to a message server or caller.
- Progress gated on `HasInflightPackets`-style counters where deletion happens only via ack or timeout.
- Acknowledgement written only after a downstream/external party responds.
- Counters or slots incremented before an operation that can fail, with decrement only on the success path.
- Early `?` returns before a spawned task that owns the release.

## How to review
For each counter, header store, or slot pool, enumerate every increment and every decrement. Confirm each increment has a decrement reachable on all exit paths: success, error, early return, timeout, and external-party failure. Check that delete/overwrite functions are actually invoked from an exposed entry point, not just defined. For gating counters, ask who controls whether items resolve and whether that party can withhold indefinitely. The property: the state machine must have a reachable path to drain or replace any tracked item regardless of external behavior.

## Variants seen
- Forwarding defers ack-writing to a downstream channel that can withhold acks, blocking upgrade completion [E1](https://bugbountylibrary.com/r/h1%3A2914705.md).
- Monotonic header append with an unused removal keeper and no message-server path, so reorgs cannot be remediated [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-04.md).
- Slot reserved before a fallible call; early error return leaks the slot and deadlocks the prover [E3](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.10.md).

## Impact and severity
Led to permanently unupgradable channels [E1](https://bugbountylibrary.com/r/h1%3A2914705.md), halted observer consensus and broken trustless proofs [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-04.md), and a deadlocked prover halting rollup proofs [E3](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.10.md). Severity rises when the stuck state is permanent and an external or adversarial party controls resolution.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A2914705.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-04.md
- E3: https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.10.md
