# Failure in endpoint can cause minting more than one NFT with the same token id in different chains

Failed LayerZero message not marked consumed lets a bridged GovNFT be re-minted via retryMessage, duplicating the same tokenId across two chains.

- Payout: Contest reward
- Severity: medium
- Program: Tigris Trade
- Credited: HE1M
- Disclosed: 2023-02-17
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-12-tigris-findings/issues/150
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-tigris%3AM-05
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:race-condition

**Target:** GovNFT cross-chain bridge (LayerZero lzReceive/retryMessage)
**Root cause:** lzReceive records a failed message in failedMessages but never marks the nonce as consumed, so a message that later succeeds via a second delivery can still be replayed through retryMessage.
**Steps:**
1. Bob calls `crossChain` to bridge tokenId X from chain B to chain A; NFT burnt on B.
2. Endpoint delivers `lzReceive` on A with low gas; excessivelySafeCall fails, message stored in `failedMessages[chainB][addr][nonce]`.
3. Endpoint re-delivers with enough gas; `lzReceive`->`nonblockingLzReceive`->`_bridgeMint` mints X on A.
4. Bob calls `crossChain` to bridge X back from A to B; burnt on A, minted on B.
5. Bob calls `retryMessage` on A for the still-stored failed message; `_bridgeMint` mints X again on A.
6. Bob now holds tokenId X on both chains.
**How found:** Code reading of the lzReceive failure path: noticed failed messages are stored but not flagged consumed, and that _bridgeMint's existence check only blocks retry while the NFT is still held on that chain.
**Exploitation:** Attacker waits for or induces a failed delivery (low gas / endpoint lag), lets the retried delivery mint the NFT, bridges it away to free the tokenId slot, then calls retryMessage to mint a second copy on the original chain; can repeat for more copies.
**Escalation:** Repeating the bridge/retry cycle yields multiple NFTs with the same tokenId across chains, each earning per-chain platform profits and sellable.
**Insight:** In bridge/FSM designs, a message that can be both 'failed' and 'delivered' is a double-spend: check whether the failure path and the success path share a consumed-nonce guard, and whether the mint's existence check can be bypassed by moving the asset off-chain first.
