# Unvalidated external data poisons trusted state

Is the value stored or trusted the same one the verification path proved, or bound to a trusted local reference?

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

## How it works
A value crosses a trust boundary — a block number in calldata, a UTXO set from a node, a vk root in public inputs — and is then stored in shared state or treated as final. The assumption that breaks: that the value the code *records or trusts* is the same value the verification path *proved*. When the two are decoupled, an attacker supplies metadata that passes shallow checks and lands in persistent shared state (or is trusted as final), while the real proof path derives its own independent copy.

## Where it shows up
- A field parsed from `extraData`, calldata, or clone args later written to a registry, while the proof/oracle path derives its own copy independently [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-2.md).
- Public inputs carrying an allowlist or root where the final verifier re-checks only the vkey hash and public-values hash, not the root itself [E3](https://bugbountylibrary.com/r/c4%3A2025-09-succinct%3AM-01.md).
- Node/RPC queries with confirmation thresholds set to zero, so mempool or unconfirmed data is treated as spendable or final [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-09.md).

## How to review
Trace the exact value from parse to store or trust. The invariant: every value written to trusted or shared state, or treated as final, must be the same value the verification path consumed, or be bound to a trusted local reference. Concretely: does the verifier compare the supplied root against a locally held trusted value, not just a hash of other fields [E3](https://bugbountylibrary.com/r/c4%3A2025-09-succinct%3AM-01.md)? Does the stored `l2BlockNumber` equal the one derived from the bisection trace [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-2.md)? Is `minConfirmations` non-zero for third-party inputs [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-09.md)?

## Variants seen
- Unvalidated block number passed as clone args and written to a shared anchor registry, poisoning it for all future games of that type [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-2.md).
- Recursion vk root left unbound to the trusted allowlist, admitting unauthorized circuits [E3](https://bugbountylibrary.com/r/c4%3A2025-09-succinct%3AM-01.md).
- Unconfirmed UTXOs accepted as spendable inputs, enabling griefing of outbound transactions — a trust-of-source variant, not stored state [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-09.md).

## Impact and severity
Ranged from targeted griefing [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-09.md) to persistent denial of service across a whole game type [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-2.md) and acceptance of unauthorized proofs [E3](https://bugbountylibrary.com/r/c4%3A2025-09-succinct%3AM-01.md). Severity rose where the poisoned value was shared state (registry, allowlist) rather than per-transaction, because one write blocks or admits everything afterward.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-09.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-2.md
- E3: https://bugbountylibrary.com/r/c4%3A2025-09-succinct%3AM-01.md
