Open c4-submissions opened 1 year ago
0xA5DF marked the issue as duplicate of #439
0xA5DF marked the issue as sufficient quality report
alcueca changed the severity to 2 (Med Risk)
alcueca marked the issue as satisfactory
alcueca marked the issue as selected for report
From the sponsor:
Although, losing assets seems possible in paper, it is certain this would ever happen in production since the initial set up of the system namely the addition of new chains or any tokens would all fail, the only functioning branch for deposits would be the Arbitrum Branch that circumvents these checks and would not have any issues withdrawing assets. There would not be any branches in remote networks since any messages setting up the connection new branches and the root chain would fail due to the validation issue being described.
0xLightt (sponsor) confirmed
Lines of code
https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L1212 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/BranchBridgeAgent.sol#L943
Vulnerability details
When bridge agent contracts communicate through the LayerZero endpoint, the source contract encodes the
_destination
parameter of theILayerZeroEndpoint.send
call by concatenating the destination address (first) and the source address (second):When the message is received on the destination chain, the destination agent validates that the sending address is correct after decoding it from the last 20 bytes of the
_srcAddress
parameter in theILayerZeroReceiver.lzReceive
call:This byte selection is however incorrect, because when calls pass by actual LayerZero logic the
_srcAddress
inlzReceive
is not equal to the_destination
passed tosend
.In a real-world scenario, by looking up the last bytes of
_srcAddress
, the destination agent will always extract its own address instead of the remote source contract's and the validation this address maps to a valid sender on the source chain will consequently always fail.Impact
Since the faulty logic is a single entry point for communication between chains, it is also a single point of failure, so this vulnerability effectively shuts down the whole branch-to-root and root-to-branch inter-chain communication.
An example high-severity impact scenario is: if after the contracts are deployed any tokens are added and bridged (i.e. out of a branch chain), these will remain permanently locked in the source chain's BranchPort as this vulnerability does not prevent the source operations from completing. The tokens will not be recoverable because:
Proof of Concept
This vulnerability can be verified by instantiating a BranchBridgeAgent and a RootBridgeAgent contract and connecting them via LayerZero's mock endpoint.
This mock, much like the productive endpoint, inverts the order of the bytes in
_destination
and_srcAddress
(relevant code below), effectively breaking the assumption that these are equal and enabling the reproduction of the issue:A full runnable foundry test showing the failure in an integrated scenario is below:
Tools Used
Code review, Foundry
Recommended Mitigation Steps
The following changes fix the inter-chain integration:
It is also recommended to add tests for agents in an integration scenario that leverages the LzEndpointMock.sol contract provided by the LayerZero team, who use it for their own testing.
Assessed type
en/de-code