Since neither depositTokens
or withdrawTokens
are protected from re-entrancy, it is possible for an attacker to manipulate the protocol into the belief that a bridged token has not been escrowed. This can be exploited to create tokens which cannot be unbridged.
In this scenario, let's an attacker with a collectionL1
token that originates on Ethereum L1 (i.e. it is an Ethereum-native ERC-721 currently in circulation and not an IERC721Bridgeable
).
First, the attacker calls depositTokens
and bridges the token onto Starknet, and then withdraws proxy token from the Starknet bridge.
Following this, the attacker then invokes escrow_deposit_tokens
to initialize the process of unbridging the token back on the L1. Importantly, the attacker specifies their own malicious contract address as the req.ownerL1
receiver.
On Ethereum, the attacker calls withdrawTokens
, which underlyingly usessafeTransferFrom
to transfer tokens, consequently invoking the onERC721Received
callback on the attacker's malicious destination contract.
Since the L1 Bridge
contract does not protect from re-entrancy, it is possible for the malicious contract to make a re-entrant invocation of depositTokens
to re-deposit the token whilst the withdrawal from the escrow is still ongoing. Crucially, because the _withdrawFromEscrow
flow does not adhere to the Checks, Effects, Interactions pattern, we can see that after the attacker's deposit operation concludes, the Escrow
contract makes the invalid assertion that _escrow[collection][id] = address(0x0)
, even though this token has indeed been escrowed.
After this, the token is bridged back to Starknet.
At this point in the attack, the attacker has successfully bridged an Ethereum-native token to Starknet, but the Bridge
on Ethereum believes that the native token it holds has not been escrowed:
It is now impossible for the token to be unbridged back on Ethereum Mainnet, since invocations to withdrawTokens
will correctly identify the correct mainnet address of the bridged token via _verifyRequestAddresses
, but the bridged token will fail to return true for isEscrowed
:
Consequently, the Bridge
contract will attempt to mintFromBridge
, resulting in revert
:
This makes it impossible to remove the token from the bridge.
It is possible for malicious users to prevent tokens from being ever bridged back from Ethereum Mainnet.
It is also plausable that the machinations of complex dependent protocols may inadvertently lock up tokens on the Bridge
if deposits were to be invoked re-entrantly, for example, based upon the dictation of an order book at a cross-chain hub.
Manual Review
Follow the CEI pattern:
Impact: - NFT already bridged won’t be bridgeable anymore without being stuck. Likelyhood: Low. - Attackers will corrupt their own tokens, deploying a risky contract interacting with an upgradable proxy. They have to buy and sell them without real benefits, except being mean. Some really specific and rare scenario can also trigger that bug.
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.