The current implementation of the withdrawTokens function on L1 Bridge introduces a crucial security risk where ERC721 tokens could become permanently locked within the escrow contract if the receiving address does not support the ERC721TokenReceiver interface.
When a user calls withdrawTokens to withdraw ERC721 tokens received from L2, the function attempts to transfer tokens from the escrow.
The vulnerability arises in the _withdrawFromEscrow function, which handles the transfer of tokens from the escrow contract back to the user's L1 address (req.ownerL1):
The escrow contract attempts to transfer the tokens using safeTransferFrom. The safeTransferFrom method ensures that the recipient contract implements the ERC721TokenReceiver interface. If the recipient (req.ownerL1) is a contract that does not support receiving ERC721 tokens (i.e., it does not implement ERC721TokenReceiver), the transfer will revert. This leads to the token being permanently locked in the escrow contract.
Users who have their L1 receiving address set to a contract that doesn't support ERC721TokenReceiver will be unable to complete their withdrawals and their tokens will be permanently locked in the escrow contract.
Manual Review
Consider using transferFrom() instead of safeTransferFrom() when transferring the tokens back to the owner in _withdrawFromEscrow. This will allow the transfer to succeed even if the owner on L1 is not an ERC721 receiver.
Impact: High, NFT will be stuck in L2 bridge. Likelyhood: Very low, sending NFT to a contract not implementing that function would almost be a user error.
Impact: High, NFT will be stuck in L2 bridge. Likelyhood: Very low, sending NFT to a contract not implementing that function would almost be a user error.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.