# Withdrawal transactions can get stuck if output root is reproposed

OptimismPortal blocks reproving a withdrawal under a new L2 output index, so if a proven output root is challenged and replaced, the withdrawal can never finalize and funds stay stuck.

- Payout: Contest reward
- Severity: medium
- Program: Optimism
- Credited: Allarious
- Disclosed: 2023-01-19
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-01-optimism-judging/issues/53
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-01-optimism%3AM-13
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** OptimismPortal / L2OutputOracle withdrawal proving
**Root cause:** proveWithdrawalTransaction requires the reproof to use the same _l2OutputIndex as the original proof, so once that output root is deleted and a different block is proposed at a new index, the withdrawal hash can never be re-proven against the new root.
**Steps:**
1. Call `proveWithdrawalTransaction(tx, _l2OutputIndex, outputRootProof, withdrawalProof)` to record `provenWithdrawals[withdrawalHash]` with that index and outputRoot.
2. Challenger deletes the output at `_l2OutputIndex`; proposer submits a different output root at a new index that lacks the withdrawal.
3. Attempt to reprove: `require(provenWithdrawal.timestamp == 0 || (_l2OutputIndex == provenWithdrawal.l2OutputIndex && outputRoot != provenWithdrawal.outputRoot))` reverts because the new index differs.
4. finalizeWithdrawalTransaction can never succeed; no refund path exists at the OptimismPortal level.
**How found:** Code-reading of the reproof require in OptimismPortal against the L2OutputOracle update semantics: noticed reproof is pinned to the original l2OutputIndex, so a changed output root at a new index can never be re-proven.
**Exploitation:** A malicious or faulty proposer submits an output root, lets a user prove a withdrawal against it, then has the output challenged/deleted and proposes a replacement root without the withdrawal; the user's proof is permanently bound to the dead index, locking bridged tokens.
**Escalation:** Proposer can target many withdrawals or submit an all-true output root so users front-run each other into locking proofs; proposer+sequencer collusion locks deposits.
**Insight:** When a proof is bound to an index into a mutable oracle, check whether the oracle can delete/replace entries at new indices; a same-index reproof guard can permanently orphan proofs.
