Open code423n4 opened 1 year ago
The submission is a bit difficult to follow. Needs judge perusal prior relaying to the sponsors.
0xSorryNotSorry marked the issue as low quality report
Besides being very difficult to follow and understand, there are many assumptions on trust assumption violations.
Kindly invite the sponsor's thoughts on this. @deanamiel
deanamiel (sponsor) confirmed
berndartmueller marked the issue as primary issue
berndartmueller marked the issue as selected for report
After a more thorough review, it is evident that the InterchainTokenService.expressReceiveTokenWithData
, and, under certain conditions such as the use of ERC-777 tokens, InterchainTokenService.expressReceiveToken
functions are vulnerable to reentrancy due to violating the CEI-pattern.
Consequently, funds can be stolen by an attacker from actors who attempt to fulfill token transfers ahead of time via the express mechanism. Thus, considering this submission as a valid high-severity finding.
Hats off to the wardens who spotted this vulnerability! 🏆
Per discussion with the judge (@berndartmueller), removing the low quality
label on their behalf.
Lines of code
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L467-L487
Vulnerability details
Description
A token transfer can be express delivered on behalf of another user, also when the call contains data to be executed:
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L467-L487
The issue here is that check effects interactions is not followed.
There are a two of attack paths here with varying assumptions and originating parties:
Attacker: Anyone, assuming there are third parties providing
expressReceiveTokenWithData
on demand with on-chain callAn attacker sends a large token transfer to a chain with a public mempool.
Once the attacker sees the call by Axelar to
AxelarGateway::exectute
in the mempool they front run this call with a call to the third party providingexpressReceiveTokenWithData
.The third party (victim) transfers the tokens to the
destinationAddress
contract. Attacker is now+amount
from this transfer.expressExecuteWithInterchainToken
on thedestinationAddress
contract does a call toAxelarGateway::exectute
(which can be called by anyone) to submit the report and then a reentry call toInterchainTokenService::execute
theircommandId
. This performs the second transfer from theTokenManager
to thedestinationAddress
(since the_setExpressReceiveTokenWithData
has not yet been called). Attacker contract is now+2x amount
, having received both the express transfer and the original transfer._setExpressReceiveTokenWithData
is set but thiscommandId
has already been executed. The victims funds has been stolen.AxelarGateway operator, assuming there are third parties providing
expressReceiveTokenWithData
off-chain.The operator does the same large transfer as described above. The operator then holds the update to
AxelarGateway::execute
and instead sends these instructions to their maliciousdestinationContract
. When theexpressReceiveTokenWithData
is called, this malicious contract will do the same pattern as described above. CallAxelarGateway::execute
thenInterchainTokenService::execute
.The same attacks could work for tokens with transfer callbacks (like ERC777) with just the
expressReceiveToken
call as well.Impact
With a very large cross chain token transfer a malicious party can use this to steal the same amount from the express receive executor.
If this fails, since it relies on front running and some timing, the worst thing that happens for the attacker is that the transfer goes through and they've just lost the transfer fees.
Note to judge/sponsor
This makes some assumptions about how trusted an operator/reporter is and that there are possibilities to have
expressReceiveTokens
to be called essentially on demand ("ExpressReceiveAsAService"). If these aren't valid please regard this as a low just noting the failure to follow checks-effects-interactions inexpressReceiveToken
/WithData
.The existence of
expressReceive
implies though that there should be some kind of service providing this premium service for a fee.Proof of Concept
Test in
tokenService.js
:And
its/test/ExpressRecipient.sol
:Tools Used
Manual audit
Recommended Mitigation Steps
Consider doing
_setExpressReceiveTokenWithData
before external calls.Assessed type
Reentrancy