# Signature verification loop logic flaws

Verifier flags defaulting permissive, loop-variable aliasing, or empty signature arrays skipping checks

_Area: Web authentication and account takeover. Seen in 2 disclosed reports; latest 2026-10-27. Updated 2026-11-01._

## How it works
Signature verification is a loop over references, keys, or signatures, and the result is a flag or pointer that the loop is supposed to set. The assumption that breaks is "the loop always runs and binds the right element." Three ways it fails: the flag starts permissive and is only flipped inside the loop, so a zero-length collection skips verification entirely [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md); the loop takes the address of a range variable that is reused each iteration, so the pointer ends up on the last element regardless of which one matched [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md); or the check delegates to a wrapper whose underlying binding can be swapped, so the digest it returns is forged [E1](https://bugbountylibrary.com/r/h1%3A2208860.md). In each case the code looks like it verifies, but the invariant "verified means a real key checked this exact content" never holds.

## Where it shows up
- A boolean like `is_valid = True` (or `verified`, `ok`) initialized before a loop and only set False inside it [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md)
- Loops over `signatures`, `keys`, `references`, or `certs` where an empty or single-element array is a valid input
- Go code taking `&rangeVar` inside a `for ... range` loop in signature, auth, or selection logic (pre-1.22 semantics) [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md)
- Security checks that call a JS wrapper (e.g. `crypto.Hash`) whose native binding prototype is reachable via an internal symbol [E1](https://bugbountylibrary.com/r/h1%3A2208860.md)
- Deserializers that accept a JWS/JWT object and return a payload without an explicit key lookup

## How to review
State the invariant: verification succeeds only if at least one signature/reference was checked against a trusted key and matched the exact bytes being consumed. Check that the flag defaults to deny (False) and is set True only after a successful comparison; that empty collections are rejected explicitly; that the matched element is bound by value or copied, not by address of a range variable; and that the digest/hash primitive cannot be overridden by untrusted code. For each loop, ask: what happens on zero iterations, and which element does the result actually point to?

## Variants seen
- Permissive default flag plus empty signatures array in JWS JSON deserialization [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md)
- Loop variable capture binding `ref` to the last SignedInfo reference in Go XML DSig [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md)
- Wrapper prototype protection not covering the underlying C++ binding, allowing forged checksums [E1](https://bugbountylibrary.com/r/h1%3A2208860.md)

## Impact and severity
All three yield signature bypass without a key: forged payloads accepted as verified [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md), swapped signed content passing validation [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md), and forged protected modules gaining policy permissions [E1](https://bugbountylibrary.com/r/h1%3A2208860.md). Severity is high because the bypass is unauthenticated and silent; it worsens when the verifier is a shared library used across many services.

## Why fixes fail
Fixes that only patch the loop body miss the empty-collection path [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md) or the aliasing slot [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md); the root cause is the initialization and binding, not the comparison.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A2208860.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-479m-364c-43vc.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-6v38-4h7w-rj9h.md
