Open c4-bot-2 opened 11 months ago
DadeKuma marked the issue as duplicate of #408
DadeKuma marked the issue as sufficient quality report
0xean marked the issue as satisfactory
This submission should not be considered a duplicate of #408, as the affected code is different. Here, the root cause lies within the ZEVM, in evm_hooks.go#L141 and evm_hooks.go#L216, where the Sender
is incorrectly set.
In contrast, #408 is about the zetaclient, specifically, utils.go#L123, incorrectly setting the Sender
of an inbound in the GetInboundVoteMsgForDepositedEvent
function.
Additionally, #285 should be duped to #407 instead of #408.
Thanks for having a second look on this!
agreed
0xean marked the issue as not a duplicate
0xean marked the issue as primary issue
0xean marked the issue as selected for report
lumtis (sponsor) confirmed
Lines of code
https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/evm_hooks.go#L141 https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/evm_hooks.go#L216
Vulnerability details
Impact
If an intermediary contract is used on the zEVM when interacting with the
ZetaConnectorZEVM
contract or ZRC-20 tokens, potential refunds are sent to the transaction signer instead of the intermediary contract, allowing users to steal assets by crafting a cctx that fails and refunds the assets to them.Determining the validity of the message call via the
ZetaInteractor.isValidMessageCall
modifier is unreliable.Proof of Concept
zEVM transactions are post-processed in the
PostTxProcessing
function of thex/crosschain
module. Specifically, the goal is to parse and processZetaSent
and ZRC-20Withdrawal
events and send them to the corresponding, external receiver chains.Any emitted
ZetaSent
events are parsed and processed in theProcessZetaSentEvent
function. Similarly, ZRC-20Withdrawal
events are processed in theProcessZRC20WithdrawalEvent
function.Both functions create a
MsgVoteOnObservedInboundTx
message in lines139-154
and214-228
.However, the
Sender
is set to theemittingContract
address in line141
and216
, which is the address of the transaction signer (i.e., sender -tx.origin
). In the very special case that the transaction is a contract creation transaction, theTo
address is set tonil
, and thus theSender
is set tonil
as well.In both cases, it is problematic as the cctx's
Sender
is used in case the outbound cctx is reverted and will be set as the receiver of the refund. As a result, the refund is potentially sent to the wrong recipient.Moreover, the
Sender
is provided to theZetaConnectorEth.onReceive
(or non-eth connector) function as thezetaTxSenderAddress
address. This sender address can be used to implement access protection on the receiving contract by using theZetaInteractor.isValidMessageCall
modifier. However, as thezetaTxSenderAddress
is unreliably set (always to the transaction signer's address), this limits the functionality and prevents the use of an intermediary contract on the zEVM.Similarly, in the
HandleEVMDeposit
function, calling theProcessLogs
function to process any logs that are a result of a zEVM deposit, and providing themsg.Receiver
(i.e.,to
) as theemittingContract
address, results in similar issues.Tl;dr
Using an intermediary contract on the zEVM that interacts with the
ZetaConnectorZEVM
contract causes refund issues and access protection issues on the receiving contract.Additionally, interacting with the
ZetaConnectorZEVM
contract on the zEVM, as part of a contract creation transaction, is discouraged and leads to lost assets when attempting to refund a failed cctx. This should be clearly documented to prevent users from losing assets.Tools Used
Manual review
Recommended mitigation steps
Consider using the
zetaTxSenderAddress
address of theZetaSent
event as well as thefrom
address of theWithdrawal
event as theSender
of the cctx.Assessed type
Other