# CrossDomainMessenger does not successfully guarantee replayability, can lose user funds

L1CrossDomainMessenger forwards all remaining gas to target, so a gas-hungry target can leave too little gas to record failedMessages, bricking replayable withdrawals permanently.

- Payout: Contest reward
- Severity: medium
- Program: Optimism
- Credited: obront
- Disclosed: 2023-03-20
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-03-optimism-judging/issues/96
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-03-optimism%3AM-1
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:dos

**Target:** L1CrossDomainMessenger / OptimismPortal withdrawal finalization
**Root cause:** L1CrossDomainMessenger calls the target with gas() (all remaining gas) instead of _minGasLimit, so the 1/64 retained after the call can fall below the ~23,823 gas needed to set failedMessages[versionedHash]=true, while OptimismPortal still has enough gas to mark the withdrawal finalized.
**Steps:**
1. User withdraws via L1CrossDomainMessenger with a _minGasLimit that is too low, or a target that consumes more than _minGasLimit.
2. OptimismPortal.finalizeWithdrawalTransaction sends >= _minGasLimit*64/63 + 200000 gas to L1CrossDomainMessenger via SafeCall.callWithMinGas.
3. L1CrossDomainMessenger calls target with gas() (all remaining), target consumes it all and reverts.
4. Remaining gas after the call is _minGasLimit/63 + 3125; if < 23,823 (i.e. _minGasLimit < 1,303,974) the failedMessages write reverts.
5. Portal already marked tx finalized and cannot be re-called; messenger never recorded failure, so replay is impossible and funds are stuck.
**How found:** Reasoned about the 63/64 gas forwarding rule: noticed SafeCall.callWithMinGas guarantees the callee won't revert but not that the caller retains enough gas afterward, then computed the leftover gas (_minGasLimit/63 + 3125) versus the 23,823 gas needed to write failedMessages and found a gap.
**Exploitation:** Not an attacker-driven exploit; triggered by a user's own withdrawal when the target consumes more gas than _minGasLimit (or _minGasLimit is set too low), causing the messenger's failure-recording path to run out of gas after the Portal has finalized.
**Insight:** When a contract relies on the 1/64 gas retention to run post-call bookkeeping (like recording failures for replay), check whether it forwards gas() rather than a bounded amount; the retained 1/64 shrinks with the forwarded gas and can drop below the bookkeeping cost.
