# Signature replay via unbound digest

Does the signed digest bind nonce, chain/domain, deadline, session and outcome fields, and is the nonce consumed on every path?

_Area: Smart contract access control and control flow. Seen in 82 disclosed reports; latest 2026-09-16. Updated 2026-10-23._

## How it works
A signature authorizes a state transition, but the signed digest does not commit to the state it acts on. If the digest omits a per-party nonce, a chain/domain id, a deadline, a session id, or an outcome-determining field, the same signature stays valid after that state changes. The verifier answers "was this signed by the right key?" but not "is this signature still meant for the current state?" A stale or duplicated authorization can then be replayed. Scope: this entry covers signature-digest replay. Proof-replay (e.g. Merkle) and storage-replay (state wiped by migration) are adjacent, not the same root cause.

## Where it shows up
- Signed structs (upnl, prices, ballots, registration data) that commit to values but not to party nonces, state versions, or outcome fields [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-14.md)[E3](https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md)[E6](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md).
- State-mutating paths (liquidation, admin, registration) that change balances but never bump the nonce the signature is gated on [E3](https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md)[E6](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md).
- Forwarder/paymaster entrypoints that decode only request.data and skip signature, domainSeparator and nonce checks, delegating them to a hook that is not always run [E1](https://bugbountylibrary.com/r/dhl%3A20260916-nimiq.md).
- Per-call signatures whose nonce is consumed only on success, so a reverted batch leaves each call valid [E5](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md).
- Bytes appended to a signature (validUntil/validAfter) parsed as policy but excluded from the hashed message [E8](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md).
- Storage keyed only by logical identity (account, backup, index) with blind overwrite, so stale session data passes verify [E7](https://bugbountylibrary.com/r/c4%3A2025-11-swafe%3AM-01.md).

## How to review
Enumerate every signed payload and ask: does the digest include a nonce/version bumped on every state change it authorizes, plus chainId, deadline, and every field that determines the outcome? For each state-mutating function, confirm the nonce is bumped on all paths, including liquidation and admin. For forwarder entrypoints, confirm signature/nonce checks run in the entrypoint itself, not only in a hook. For session calls, confirm signature scope matches the full payload and nonce consumption is not coupled to execution success. The invariant: a signature must be valid for exactly one state transition and unusable afterward. A nonce present but not bumped on one path is still a bug; a nonce absent entirely is the same bug, not a safe design.

## Variants seen
- Missing party nonce in liquidation signature, stale upnl reused [E3](https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md).
- Ballot digest omits the submitted pubkey, votes for different keys collide [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-14.md).
- Missing deadline lets an old registration signature be replayed indefinitely [E6](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md).
- Forwarder entrypoint skips signature/nonce, drains standing approvals [E1](https://bugbountylibrary.com/r/dhl%3A20260916-nimiq.md).
- Per-call nonce consumed only on success, reverted batch replayable [E5](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md).
- Appended validity-window bytes not bound to the signed digest [E8](https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md).
- Stale session shares overwrite fresh ones, blocking recovery [E7](https://bugbountylibrary.com/r/c4%3A2025-11-swafe%3AM-01.md).

## Why fixes fail
Adding a nonce only to the main path but not liquidation/admin paths leaves the window open [E3](https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md)[E6](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md). Consuming the nonce only on success leaves reverted batches replayable [E5](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md). Binding a session key to ciphertext but not to the storage key still allows overwrite [E7](https://bugbountylibrary.com/r/c4%3A2025-11-swafe%3AM-01.md).

## Impact and severity
Led to draining all cross-chain funds via a swapped key [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-14.md), unfair liquidation wiping funds from all parties [E3](https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md), theft of standing approvals [E1](https://bugbountylibrary.com/r/dhl%3A20260916-nimiq.md), and forced bond transfers [E6](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md). Severity is high: replay turns one valid authorization into repeated value movement. Worse when the signed value can go stale silently and no on-chain nonce guards the path.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20260916-nimiq.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-14.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AH-1.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2023-03-optimism%3AH-2.md
- E5: https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-02.md
- E6: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-07.md
- E7: https://bugbountylibrary.com/r/c4%3A2025-11-swafe%3AM-01.md
- E8: https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01.md
