Cross-chain messages might be processed out-of-order, leading to failed transactions and dApps that are not working as expected.
Proof of Concept
Cross-chain messages can be sent between external chains by using the ZetaConnectorEth.send function. This function emits the ZetaSent event that is subsequently picked up by the ZetaChain observers and voted upon.
Such a cross-chain transaction is considered valid (finalized), once a quorum of observers has voted on the transaction and verified the legitimacy of the transaction. This process naturally takes a certain amount of time, as the observers wait for the including block (on the external chain) to be confirmed by a reasonable amount of subsequent blocks. Additionally, observers are not 100% synchronized, meaning that some observers might have seen the including block earlier than others.
As a result, cross-chain transactions, or inbound cctxs in general, are not guaranteed to be finalized in the order they were sent from the external chain.
This can lead to a situation where a contract on an external chain that sends two consecutive cross-chain messages and expects the second message to be processed after the first message, is not guaranteed to be processed in the correct order.
For example, consider the simplified example of a staking dApp which sends multiple consecutive cross-chain messages in the same block or transaction (please ignore the reasoning why a user would stake and immediately unstakes, this should just demonstrate the dependency on the order of the messages):
stake
unstake
Those two messages have to be in order. If message 2 (unstake) is executed before message 1 (stake), the transaction reverts on the destination chain as there is no stake to unstake.
Even if the dApp would incorporate a nonce in the cross-chain message, the receiving contract on the destination chain would reject the out-of-order message as the nonce is not the next expected nonce and revert the transaction.
Tools Used
Manual review
Recommended mitigation steps
Consider adding the option to enforce message ordering per sender and source chain, similar to LayerZero's message ordering feature.
Lines of code
https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/protocol-contracts/contracts/evm/ZetaConnector.eth.sol#L31-L45
Vulnerability details
Impact
Cross-chain messages might be processed out-of-order, leading to failed transactions and dApps that are not working as expected.
Proof of Concept
Cross-chain messages can be sent between external chains by using the
ZetaConnectorEth.send
function. This function emits theZetaSent
event that is subsequently picked up by the ZetaChain observers and voted upon.Such a cross-chain transaction is considered valid (finalized), once a quorum of observers has voted on the transaction and verified the legitimacy of the transaction. This process naturally takes a certain amount of time, as the observers wait for the including block (on the external chain) to be confirmed by a reasonable amount of subsequent blocks. Additionally, observers are not 100% synchronized, meaning that some observers might have seen the including block earlier than others.
As a result, cross-chain transactions, or inbound cctxs in general, are not guaranteed to be finalized in the order they were sent from the external chain.
This can lead to a situation where a contract on an external chain that sends two consecutive cross-chain messages and expects the second message to be processed after the first message, is not guaranteed to be processed in the correct order.
For example, consider the simplified example of a staking dApp which sends multiple consecutive cross-chain messages in the same block or transaction (please ignore the reasoning why a user would stake and immediately unstakes, this should just demonstrate the dependency on the order of the messages):
stake
unstake
Those two messages have to be in order. If message 2 (
unstake
) is executed before message 1 (stake
), the transaction reverts on the destination chain as there is no stake to unstake.Even if the dApp would incorporate a nonce in the cross-chain message, the receiving contract on the destination chain would reject the out-of-order message as the nonce is not the next expected nonce and revert the transaction.
Tools Used
Manual review
Recommended mitigation steps
Consider adding the option to enforce message ordering per sender and source chain, similar to LayerZero's message ordering feature.
Assessed type
Other