The CollectionManager::_setL1L2AddressMapping
is designed to map one L1 address to an L2 address and similarly map that L2 address to the L1 address. Furthermore, if force
is passed as True
to CollectionManager::_setL1L2AddressMapping
, this operation is carried out even if these addresses had any previous mappings before the function call.
The vulnerability of this function lies in the fact that when the CollectionManager::_setL1L2AddressMapping
function is called with force
passed as True
, previous mappings are only partially over-written since the new addresses are mapped without resetting any previous mappings in both ramifications. See https://github.com/Cyfrin/2024-07-ark-project/blob/273b7b94986d3914d5ee737c99a59ec8728b1517/apps/blockchain/ethereum/src/token/CollectionManager.sol#L151-L165
Since the CollectionManager::_setL1L2AddressMapping
function does not reset any previous mappings before mapping the two addresses together, this leads to a situation where two L1 addresses can be mapped to the same L2 address or two L2 addresses be mapped to the same L1 address. This can cause confussion to the users of the protocol.
Manual Review
Foundry
Proof of Concept:
Call the CollectionManager::_deployERC721Bridgeable
passing it an L2 address say collectionL2
. This function will deploy a contract and map the contract address say L1Address
to collectionL2
and vice versa. See https://github.com/Cyfrin/2024-07-ark-project/blob/273b7b94986d3914d5ee737c99a59ec8728b1517/apps/blockchain/ethereum/src/token/CollectionManager.sol#L49-L70
Now call the CollectionManager::_setL1L2AddressMapping
function passing it the following parameters: newL1Address
, collectionL2
and True
. This function will in turn map newL1Address
to collectionL2
and also map collectionL2
to newL1Address
. Note that this function does not reset any previous mappings whatsoever.
Thus,
L1Address
is mapped to collectionL2
,
newL1Address
is mapped to collectionL2
, but
collectionL2
is only mapped to newL1Address
The protocol now has two L1 addresses mapped to the same L2 address but the L2 address is only mapped to one of the two L1 addresses.
Now, place the following code in the EscrowTest
contract in the Escrow.t.sol
script:
Run: forge test --match-test test_setL1L2AddressMappingDisruptsL1ToL2Mappings -vvvv
Output:
Consider resetting any previous mappings before setting any new mappings in the CollectionManager::_setL1L2AddressMapping
function as below
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.