Open sherlock-admin3 opened 5 months ago
We had a chat with LZ about this a while ago and yes, the router cannot be used in this case. However the contract we're going to use is https://etherscan.io/address/0xeCc19E177d24551aA7ed6Bc6FE566eCa726CC8a9#code and it respects the IStargateRouter interface
The contract you referenced above, i.e. StargateComposer
doesn't have the swapETH
interface:
function swapETH(uint16 _dstChainId, address payable _refundAddress, bytes calldata _toAddress, uint256 _amountLD, uint256 _minAmountLD) external;
Your options are to refactor this to either use the *RouterETH: swapETHAndCall
or the StargateComposer::swapETHAndCall
function.
Good catch @windhustler
Changed the status to 'Will fix'
The protocol team fixed this issue in PR/commit https://github.com/Tapioca-DAO/TapiocaZ/pull/174; https://github.com/Tapioca-DAO/tapioca-periph/pull/198.
GiuseppeDeLaZara
high
All ETH can be stolen during rebalancing for
mTOFTs
that hold nativeSummary
Rebalancing of ETH transfers the ETH to the destination mTOFT without calling
sgRecieve
which leaves the ETH hanging inside themTOFT
contract. This can be exploited to steal all the ETH.Vulnerability Detail
Rebalancing of
mTOFTs
that hold native tokens is done through therouterETH
contract inside theBalancer.sol
contract. Here is the code snippet for therouterETH
contract:The expected behaviour is ETH being received on the destination chain whereby
sgReceive
is called and ETH is deposited inside theTOFTVault
.By taking a closer look at the logic inside the
routerETH
contract we can see that the transfer is called with an empty payload:Notice the comment:
So
routerETH
after depositing ETH inStargateEthVault
calls the regularStargateRouter
but with an empty payload.Next, let's see how the receiving logic works.
As Stargate is just another application built on top of LayerZero the receiving starts inside the
Bridge::lzReceive
function. As the type of transfer isTYPE_SWAP_REMOTE
therouter::swapRemote
is called:Router:swapRemote
has two responsibilities:pool::swapRemote
that transfers the actual tokens to the destination address. In this case this is themTOFT
contract.IStargateReceiver(mTOFTAddress)::sgReceive
but only if the payload is not empty.As payload is empty in case of using the
routerETH
contract thesgReceive
function is never called. This means that the ETH is left sitting inside themTOFT
contract.There are several ways of stealing the balance of
mTOFT
. An attacker can use themTOFT::sendPacket
function and utilize thelzNativeGasDrop
option to airdrop the balance of mTOFT to attacker's address on the destination chain: https://docs.layerzero.network/contracts/options#lznativedrop-optionAll he has to do is specify the option type
lzNativeDrop
inside the_lsSendParams.extraOptions
and the cost of calling_lzSend
plus the airdrop amount will be paid out from the balance ofmTOFT
.As this is a complete theft of the rebalanced amount I'm rating this as a critical vulnerability.
Impact
All ETH can be stolen during rebalancing for mTOFTs that hold native tokens.
Code Snippet
Tool used
Manual Review
Recommendation
One way to fix this is use the alternative
RouterETH.sol
contract available from Stargate that allows for a payload to be sent. It is denoted as*RouterETH.sol
in the Stargate documentation: https://stargateprotocol.gitbook.io/stargate/developers/contract-addresses/mainnet This router has theswapETHAndCall
interface:The contract on Ethereum can be found at: https://www.codeslaw.app/contracts/ethereum/0xb1b2eeF380f21747944f46d28f683cD1FBB4d03c. And the Stargate docs specify its deployment address on all the chains where ETH is supported: https://stargateprotocol.gitbook.io/stargate/developers/contract-addresses/mainnet