# All ETH can be stolen during rebalancing for `mTOFTs` that hold native

Rebalancing mTOFTs via routerETH sends empty payload so sgReceive never deposits ETH, leaving it stranded in mTOFT where anyone can steal it via lzNativeGasDrop.

- Payout: Contest reward
- Severity: high
- Program: Tapioca
- Credited: 0xadrii
- Disclosed: 2024-02-14
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2024-02-tapioca-judging/issues/69
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AH-6
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm technique:source-review vuln:access-control vuln:business-logic

**Target:** Balancer.sol routerETH rebalancing and mTOFT.sgReceive
**Root cause:** routerETH.swapETH sends an empty payload, so Stargate Router skips sgReceive; the bridged ETH lands in mTOFT without being deposited into TOFTVault.
**Steps:**
1. Observe Balancer.sol rebalancing calls `routerETH.swapETH{value: valueAmount}(...)` which internally calls `stargateRouter.swap(..., bytes(""))` with empty payload.
2. On destination, Router._swapRemote only calls `sgReceive` if `_payload.length > 0`; empty payload means ETH is transferred to mTOFT but sgReceive is skipped.
3. ETH remains in mTOFT contract balance instead of being deposited to vault.
4. Attacker calls `mTOFT.sendPacket` with `extraOptions` containing `lzNativeDrop` option to airdrop mTOFT's ETH balance to attacker's address on destination chain.
**How found:** Code reading of Balancer.sol rebalancing path and Stargate routerETH source revealed the empty payload comment 'since sending to EOA'; tracing Stargate Router._swapRemote showed sgReceive is conditional on payload length, leading to the stranded ETH hypothesis and the lzNativeDrop drain vector.
**Exploitation:** Attacker waits for rebalancing to strand ETH in mTOFT, then calls sendPacket with lzNativeDrop option; the airdrop amount and _lzSend fee are paid from mTOFT's balance, draining it to attacker's chosen address.
**Insight:** When integrating cross-chain messaging, check whether the bridge helper contract sends an empty payload; if so, the destination contract's receive hook is skipped and any native/token value transferred sits unprotected in the contract balance, drainable via message options like lzNativeDrop.
