# Cap checks that ignore cumulative state

Cap or limit checked against this increment only, not the accumulated total or global state it protects

_Area: DeFi accounting and math bugs. Seen in 30 disclosed reports; latest 2026-08-20. Updated 2026-10-23._

## How it works
A cap is meant to bound a total. The bug is that the check reads only the value in front of it (this deposit, this call, this position) and ignores the accumulated or global state the cap protects. The invariant "total stays under cap" is never enforced; only "this increment is under cap" is. A second shape: the cap is computed correctly on one path, but other paths that mutate the same variable skip the re-check, so the variable drifts past the cap. A third: the cap is computed on the wrong basis (current position instead of target, or a post-change value compared to a pre-change ceiling).

## Where it shows up
- Per-call bound checked against a downstream protocol's cap, not the cumulative position [E8](https://bugbountylibrary.com/r/c4%3A2024-12-benddao-invitational%3AM-01.md).
- Cap computed in one function while settlement or earnings accrual writes the same variable without re-checking [E6](https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-03.md).
- A tracked loss (bad debt) moved out of total supply, then omitted from the cap formula that reads supply [E5](https://bugbountylibrary.com/r/c4%3A2026-04-k2%3AM-41.md).
- A tolerance multiplier applied to a post-decrement value and compared to a pre-decrement ceiling [E1](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-19.md).
- A candidate value assigned before a conditional gate, then returned on the fall-through path [E2](https://bugbountylibrary.com/r/c4%3A2023-07-pooltogether%3AM-14.md).
- Global limit derived from one underlying position rather than target vs current allocation [E3](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AH-3.md).
- Transfer hook checks solvency but not the tighter LTV threshold [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.11.md).
- A shared invariant (e.g. LUP >= HTP) enforced on most mutation paths but skipped on one [E4](https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-2.md).

## How to review
1. State the invariant: total X must never exceed cap C, across all paths.
2. Enumerate every write to X (entry points, settlement, accrual, hooks, liquidation).
3. For each cap check ask: does it read the cumulative/global value or only the increment? Does it include reclassified amounts (deficits, pending balances)?
4. Diff post-condition checks across paths that mutate the same invariant; a missing guard on one path breaks it [E4](https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-2.md).
5. For tolerance math, solve tolerance*(W-d) == W; a repeatable partial exit means bypassable [E1](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-19.md).
6. For hooks, confirm the tighter threshold (LTV), not just solvency [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.11.md).
To confirm exploitability without a PoC, trace state deltas across two calls: if the second call passes the same check the first did while the total now exceeds C, the invariant is broken.

## Variants seen
- Tolerance multiplier on post-decrement weight vs pre-decrement ceiling [E1](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-19.md).
- Pre-gate assignment returned on fall-through [E2](https://bugbountylibrary.com/r/c4%3A2023-07-pooltogether%3AM-14.md).
- Global limit throttled by smallest underlying position [E3](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AH-3.md).
- One mutation path skips the shared invariant guard [E4](https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-2.md).
- Reclassified deficit omitted from cap formula [E5](https://bugbountylibrary.com/r/c4%3A2026-04-k2%3AM-41.md).
- Settlement path skips cap re-check, causing overflow [E6](https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-03.md).
- Transfer hook checks solvency but not max LTV [E7](https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.11.md).
- Per-call check misses cumulative position [E8](https://bugbountylibrary.com/r/c4%3A2024-12-benddao-invitational%3AM-01.md).

## Impact and severity
Ranged from bypassed deposit/withdrawal caps and locked funds [E4](https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-2.md)[E8](https://bugbountylibrary.com/r/c4%3A2024-12-benddao-invitational%3AM-01.md) to DoS of withdrawals [E3](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AH-3.md) and overflow-driven DoS [E6](https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-03.md). Severity rises when the bypass is repeatable and compounds [E1](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-19.md) or locks user funds [E8](https://bugbountylibrary.com/r/c4%3A2024-12-benddao-invitational%3AM-01.md). Missing re-checks on secondary paths [E6](https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-03.md) are easy to overlook and widen impact.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-19.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-07-pooltogether%3AM-14.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AH-3.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-2.md
- E5: https://bugbountylibrary.com/r/c4%3A2026-04-k2%3AM-41.md
- E6: https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-03.md
- E7: https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.11.md
- E8: https://bugbountylibrary.com/r/c4%3A2024-12-benddao-invitational%3AM-01.md
