# Cross-chain failure strands escrowed funds

Every remote-call or deposit failure path must refund, retry, or unlock escrowed value

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2025-04-10. Updated 2026-10-25._

## How it works
A cross-chain action has two halves that fail independently. The sending side escrows or burns value, then a remote handler runs. If the remote handler reverts, aborts, or is skipped, the value is already gone from the user but never delivered or returned. The broken assumption is that a failed remote call unwinds the whole operation. In practice the messaging layer may not retry a reverting receiver [E2](https://bugbountylibrary.com/r/c4%3A2024-04-renzo%3AM-08.md), an abort branch may simply mark the transfer failed without refunding [E3](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-07.md), or a queued side effect may survive a revert that the caller thought cancelled it [E1](https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md).

## Where to show up
- Bridge receiver handlers (`xReceive`-style) that call into vaults, staking, or token contracts without catching reverts [E2](https://bugbountylibrary.com/r/c4%3A2024-04-renzo%3AM-08.md)
- Revert sources inside the receive path: TVL caps, pause flags, zero-amount mint math [E2](https://bugbountylibrary.com/r/c4%3A2024-04-renzo%3AM-08.md)
- State machines with an `Aborted`/`Failed` status set on error but no matching refund branch [E3](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-07.md)
- Refund logic that covers only one asset type or one route (e.g. ERC20-to-home-chain) and not swaps [E3](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-07.md)
- Per-call queues or pointers stored on an outer context, shared across nested calls and not snapshotted with state [E1](https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md)
- Precompile or callback dispatch that runs after the EVM frame reverted [E1](https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md)

## How to review
Enumerate every early-return and revert path in the receive/abort handler and ask, for each: does value end up back with the sender, retried, or still escrowed? The invariant: for every terminal failure state, escrowed or bridged value is either refunded to the origin or provably retryable. Check whether the messaging layer retries receiver reverts; if not, the handler must not revert on recoverable conditions. For queued side effects, verify the queue is part of the snapshotted state so a reverted frame discards its entries [E1](https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md).

## Variants seen
- Receiver revert strands L2 funds with no retry [E2](https://bugbountylibrary.com/r/c4%3A2024-04-renzo%3AM-08.md)
- Abort status set with no refund branch; refund coverage differs by asset and route [E3](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-07.md)
- Queued cross-chain messages dispatched despite a caught revert, executing transfers the caller believed cancelled [E1](https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md)

## Impact and severity
Permanent loss or freezing of user funds, medium to high. Worse when the failure is triggered by ordinary conditions (cap reached, paused) rather than attacker action, and when no admin rescue path exists.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2025-02-initia-cosmos%3AH-03.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-04-renzo%3AM-08.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-07.md
