# Unvalidated cross-chain proof or state root

Proof or state root accepted from caller without binding to canonical chain state

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2025-08-21. Updated 2026-11-01._

## How it works
A contract accepts a proof, state root, or inner-puzzle hash supplied by the caller and acts on it without checking it against the canonical, already-committed state. The broken assumption is that "if a proof verifies, the thing it proves must be legitimate." Verification only shows internal consistency of the supplied data; it says nothing about whether that data is anchored to the real chain. When the anchor check is missing or deferred, an attacker supplies their own root or hash and the contract treats it as authoritative.

## Where it shows up
- Commit/accept functions that take a parent root, previous state root, or proof as a parameter and store it without comparing to a finalized/known root.
- Validation of the same field split across two functions (accept at commit, check at finalize), leaving a window where unvalidated data is live.
- "Exit layer" or unwrap paths callable by non-owners that construct a coin/object with a target hash but never assert that hash.
- Fixed-size proof arrays (e.g. a single `bytes32[]`) in structs meant to carry multiple leaves.
- Any place a caller-chosen hash becomes the identity of an approved object.

## How to review
Identify every caller-supplied root, proof, or hash and trace where it is bound to canonical state. The invariant: a value is only acted upon after it is checked against a root the contract itself finalized or a hash it committed earlier, in the same call path that accepts it. Check that deferred checks (at finalize) are not the only gate for commit-time acceptance. For exit/unwrap paths, confirm the inner hash is asserted, not just referenced. For multi-leaf designs, confirm the calldata struct can carry a proof per leaf.

## Variants seen
- Exit path creates object with target hash but never asserts it, letting a non-approved layer pass as approved [E1](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.1.5.md).
- Parent state root validated only at finalize, not at commit, so a fake root is accepted and wins challenges [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-morphl2%3AH-2.md).
- Signature struct carries one proof array, silently capping a documented multi-leaf tree to two leaves [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md).

## Impact and severity
Led to control of a price feed [E1](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.1.5.md), chain freeze plus theft of challenge deposits [E2](https://bugbountylibrary.com/r/sherlock%3A2024-08-morphl2%3AH-2.md), and broken core multi-chain functionality [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md). Severity is high: the flaw defeats the trust boundary the proof was meant to enforce. Worse when the same unvalidated field also gates slashing or challenge outcomes, since the attacker can be both wrong and rewarded.

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.1.5.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-08-morphl2%3AH-2.md
- E3: https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.20.md
