Closed howlbot-integration[bot] closed 4 months ago
This is an intentional design decision. The aggregator should have a rescue function available in the case that the swapOut fails - this should not be the responsibility of the Router. Adding "sponsor disputed"
Sponsor's comments seem appropriate, will invalidate.
trust1995 marked the issue as unsatisfactory: Invalid
I believe the issue should be valid.
Even though there is a rescue function on the aggregator (e.g. rescueFunds()
), not only the contract owner must be aware that there are some funds that need to be rescued (which might not be immediate), but an attacker still has the ability to frontrun the owner transaction to execute swapOutV5()
and drain the tokens that have been transferred previously.
The swap on the aggregator works in a two-steps process (token.transfer()
and aggregator.swapOutV5()
) which must be done atomically in order to prevent the loss of funds. In case these steps are splitted, a malicious actor can insert the same swapOutV5()
transaction in between but with a different recipient to steal funds.
@the-eridanus can you offer comments on that?
This is invalid similar to other issues which assume behavior of the OOS aggregator contract.
Lines of code
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L304-L389 https://github.com/code-423n4/2024-06-thorchain/blob/0e02d3c221d7e546a73f25183e29500eaa63f4cf/chain/ethereum/contracts/THORChain_Aggregator.sol#L144-L216
Vulnerability details
Impact
Calling the following
_transferOutAndCallV5
function for an ERC20 token executesaggregationPayload.fromAsset.call(abi.encodeWithSignature("transfer(address,uint256)", aggregationPayload.target, aggregationPayload.fromAmount))
, which transfersaggregationPayload.fromAmount
of such token to the target aggregator. The_transferOutAndCallV5
function then calls the target aggregator'sswapOutV5
function below but suchswapOutV5
function call can revert, such as when theswapRouter.swapExactTokensForETH
function call cannot satisfyaggregationPayload.amountOutMin
. In this situation, calling the_transferOutAndCallV5
function would not revert even though_dexAggSuccess
would be false. SinceaggregationPayload.fromAmount
of such token has been transferred to the target aggregator, failing to use these transferred tokens in the target aggregator'sswapOutV5
function call and not reverting the_transferOutAndCallV5
function call cause the vault to send these transferred tokens and the recipient to receive nothing in return. As a result, the recipient losesaggregationPayload.fromAmount
of such token that she or he deserves.https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L304-L389
https://github.com/code-423n4/2024-06-thorchain/blob/0e02d3c221d7e546a73f25183e29500eaa63f4cf/chain/ethereum/contracts/THORChain_Aggregator.sol#L144-L216
Proof of Concept
The following steps can occur for the described scenario.
_transferOutAndCallV5
function for an ERC20 token.swapRouter.swapExactTokensForETH
function call does not satisfyaggregationPayload.amountOutMin
, the target aggregator'sswapOutV5
function call reverts._transferOutAndCallV5
function sendsaggregationPayload.fromAmount
of such token to the target aggregator and does not revert even though the target aggregator'sswapOutV5
function call reverts, the vault sends these transferred tokens but the recipient receives nothing in return.aggregationPayload.fromAmount
of such token that she or he deserves.Tools Used
Manual Review
Recommended Mitigation Steps
The
_transferOutAndCallV5
function can be updated to revert if_dexAggSuccess
returned by the target aggregator'sswapOutV5
function call is false.Assessed type
Token-Transfer