# Inverted or mismatched state checks

Guards comparing wrong variable, inverted boolean, or stale counter that let bad state pass

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2025-10-29. Updated 2026-10-23._

## How it works
A gate that decides whether an action is allowed reads the wrong value: the wrong variable, the wrong counter, an inverted boolean, or a field that a zeroed struct makes trivially true. The code looks like it checks state, but the check does not actually constrain the condition it was meant to. The assumption that breaks is "this guard reflects the real precondition." When the compared value diverges from the intended one, an unauthorized or impossible transition passes.

## Where it shows up
- Boolean operators combining auction/settlement conditions (`&&` where `||` is meant) [E1](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AH-13.md)
- Zeroed structs satisfying amount or payment checks after cleanup [E1](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AH-13.md)
- Permissionless transitions that promote state (e.g. to GoodStanding) without an approval gate [E2](https://bugbountylibrary.com/r/dhl%3A20260511-humacreditapprovalbypass.md)
- Time-based auto-promotion skipping a required authorization step [E2](https://bugbountylibrary.com/r/dhl%3A20260511-humacreditapprovalbypass.md)
- Two readiness gates over the same collection comparing different accessors (verifiers vs watchtowers) [E3](https://bugbountylibrary.com/r/cantina%3Aclementine_aug2025%3A3.1.1.md)
- A predicate enforced only at settlement but never at the earlier deposit/bond step [E4](https://bugbountylibrary.com/r/c4%3A2021-12-defiprotocol%3AM-07.md)

## How to review
For each gate, identify the exact invariant it should enforce and confirm the compared variable is the one that invariant depends on. Check that "empty/zero" state cannot satisfy a positive condition. For state machines, list every transition that grants power and verify each has its authorization gate, including time-triggered ones. Where multiple gates read the same collection, diff the counters/accessors they compare. Where a value is validated at settlement, check whether the same predicate should gate the earlier step that locks funds.

## Variants seen
- Inverted boolean in settlement guard lets zero-payment settlement wipe collateral [E1](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AH-13.md)
- Missing approval gate on a permissionless credit-line promotion drains pools [E2](https://bugbountylibrary.com/r/dhl%3A20260511-humacreditapprovalbypass.md)
- Mismatched counter accessor deadlocks a state machine and causes slashing [E3](https://bugbountylibrary.com/r/cantina%3Aclementine_aug2025%3A3.1.1.md)
- Settlement-only ratio check makes a bond unsettleable and burns funds [E4](https://bugbountylibrary.com/r/c4%3A2021-12-defiprotocol%3AM-07.md)

## Why fixes fail
E4 shows the check exists but only at settlement; the bond step never enforces it, so funds lock into an unrecoverable state. Fixing one gate without the paired earlier gate leaves the failure intact.

## Impact and severity
Ranged from total loss of a borrower's collateral for zero payment [E1](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AH-13.md) and ~$101K drained across pools [E2](https://bugbountylibrary.com/r/dhl%3A20260511-humacreditapprovalbypass.md) to operator slashing [E3](https://bugbountylibrary.com/r/cantina%3Aclementine_aug2025%3A3.1.1.md) and burned bonder funds [E4](https://bugbountylibrary.com/r/c4%3A2021-12-defiprotocol%3AM-07.md). Severity rises when the path is permissionless and when no cancel/refund exists.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AH-13.md
- E2: https://bugbountylibrary.com/r/dhl%3A20260511-humacreditapprovalbypass.md
- E3: https://bugbountylibrary.com/r/cantina%3Aclementine_aug2025%3A3.1.1.md
- E4: https://bugbountylibrary.com/r/c4%3A2021-12-defiprotocol%3AM-07.md
