# Verdict check-use swap in verification

Success or equality verdict applied to data or identity that changed or was mis-normalized after the check

_Area: Memory corruption and native code. Seen in 2 disclosed reports; one confirmed bounty: $560; latest 2024-03-29. Updated 2026-10-23._

## How it works
A verification step produces a verdict (pass/fail, equal/unequal, verified/retry) that is then consumed by code that assumes the verdict still describes the bytes or identity it was computed over. The assumption that breaks: that the verdict is (a) correctly normalized and (b) still bound to the same object at use time. In the evidence the verdict was wrong at the source — a success value assigned before the real work, a comparator result mis-mapped, an internal error surfaced as a retryable state — so downstream code trusted a check that never actually held.

## Where it shows up
- Error-handling paths where a success return is set early and later failure branches `goto out` without resetting it [E1](https://bugbountylibrary.com/r/h1%3A2437050.md)
- TLS/certificate initialization code with multiple early-exit branches [E1](https://bugbountylibrary.com/r/h1%3A2437050.md)
- C comparators returning strcmp-style values wrapped by normalization code [E2](https://bugbountylibrary.com/r/h1%3A387250.md)
- Equality/name-comparison wrappers with bounds like `result > 1` [E2](https://bugbountylibrary.com/r/h1%3A387250.md)
- Library code mapping internal error codes to public API return values [E3](https://bugbountylibrary.com/r/h1%3A1455411.md)
- Callers that never opted into a feature receiving its error codes [E3](https://bugbountylibrary.com/r/h1%3A1455411.md)

## How to review
For each verdict, trace the exact value returned on every exit path and confirm it reflects the completed check, not an earlier state. For comparators, verify the wrapper maps all nonzero results to "unequal" and test equality in both directions with off-by-one-length inputs [E2](https://bugbountylibrary.com/r/h1%3A387250.md). For error mapping, confirm internal errors cannot masquerade as retryable or success states, and that callers only see codes for features they enabled [E3](https://bugbountylibrary.com/r/h1%3A1455411.md). Invariant: the verdict consumed at use time must be produced by, and bound to, the same bytes/identity, with no path that returns success without performing the check.

## Variants seen
- Early success assignment overwritten, later failure branches skip cert verification setup [E1](https://bugbountylibrary.com/r/h1%3A2437050.md)
- Comparator normalization bound treats result of exactly 1 as equal [E2](https://bugbountylibrary.com/r/h1%3A387250.md)
- Internal negative error treated as retryable, leaking unexpected state to caller [E3](https://bugbountylibrary.com/r/h1%3A1455411.md)

## Impact and severity
Led to certificate verification bypass enabling MITM [E1](https://bugbountylibrary.com/r/h1%3A2437050.md), name-validation bypass [E2](https://bugbountylibrary.com/r/h1%3A387250.md), and crashes or loops in clients [E3](https://bugbountylibrary.com/r/h1%3A1455411.md). Severity rises when the verdict gates authentication (TLS/cert checks) and when the wrong state is silent rather than an explicit error.

## Why fixes fail
Partial normalization (fixing only one comparison direction) or patching one exit path leaves sibling branches returning the stale verdict [E1](https://bugbountylibrary.com/r/h1%3A2437050.md)[E2](https://bugbountylibrary.com/r/h1%3A387250.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A2437050.md
- E2: https://bugbountylibrary.com/r/h1%3A387250.md
- E3: https://bugbountylibrary.com/r/h1%3A1455411.md
