# Signature nonce not consumed on revert

Is every signed field hashed, and is the nonce consumed exactly once even when execution reverts?

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2026-04-27. Updated 2026-10-24._

## How it works
Replay protection assumes a signed nonce or validity window is authenticated and consumed exactly once. It breaks when the nonce advance is rolled back with a reverted transaction, or when the signature covers only part of the payload. Then a failed batch leaves each individual signature still valid and replayable, and unsigned metadata can be rewritten to extend a signature's life.

## Where it shows up
- Nonce consumed inside the same transaction that can revert (batch execution with revert-on-error), so the increment is undone [E1](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md).
- Signatures computed over a per-call hash rather than the full call set or payload [E1](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md).
- Metadata appended to a signature blob (validUntil/validAfter, gas limits, nonces) but excluded from the hashed message [E3](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md).
- Nonce state written without multi-party authorization: a deprecated-but-reachable handler that skips the vote tally and calls the setter directly [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md).
- A single authorized writer setting a nonce that downstream code compares for equality [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md).

## How to review
List every field parsed from a signature and confirm each is folded into the signed digest. Confirm the nonce/validity state advances in a way that survives a revert of the guarded action: either a separate storage write not rolled back, or consumed before any revertible step and not undone. Note that consuming the nonce before validation is not enough if the whole transaction reverts afterward [E1](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md). Check that signature scope matches the full payload the caller intends to authorize. For nonce-setting paths, confirm the multi-party tally actually runs. Invariant: one valid signature authorizes exactly one execution, and no field influencing acceptance is left unsigned.

## Variants seen
- Per-call signatures with nonce consumption reverted by batch failure, enabling subset replay [E1](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md).
- Deprecated msg handler bypassing multi-observer voting, letting one actor overwrite chain nonce [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md).
- Validity window appended to signature but not hashed, so relayers rewrite and replay later [E3](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md).

## Why fixes fail
Commenting out voting logic without removing reachability left the bypass live [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md). Binding only the operation hash while leaving appended validUntil/validAfter unsigned left replay open [E3](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md).

## Impact and severity
Led to replay/frontrunning of signed calls [E1](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md), chain-halting desync of cross-chain nonces by a single observer [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md), and unauthorized extension of a signed operation's lifetime [E3](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md). Severity rises when one actor can write shared nonce state or when replay crosses trust boundaries.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-01.md
- E3: https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md
