# CowSwap SwapGuard: arbitrary external call drains settlement DAI

CowSwap SwapGuard's envelope() executed arbitrary external calls, letting an attacker transferFrom DAI held by the GPv2Settlement contract, stealing ~$120k.

- Payout: Real-world hack
- Severity: high
- Program: - CowSwap
- Analysis by: DeFiHackLabs
- Disclosed: 2023-02-07
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-02/CowSwap_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230207-cowswap
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity vuln:access-control vuln:business-logic

**Target:** SwapGuard contract / GPv2Settlement allowance
**Root cause:** SwapGuard.envelope() accepted an arbitrary array of {target, value, callData} interactions and executed them without validating target or calldata, so any caller could make SwapGuard invoke arbitrary contracts on its own behalf.
**Steps:**
1. Fork mainnet at block 16574048.
2. Read DAI.balanceOf(GPv2Settlement) and cap by DAI.allowance(GPv2Settlement, swapGuard).
3. Build calldata `transferFrom(address,address,uint256)` with from=GPv2Settlement, to=attacker, amount.
4. Wrap in SwapGuard.Data{target: DAI, value: 0, callData}.
5. Call `swapGuard.envelope(interactions, vault, tokens, tokenPrices, balanceChanges, allowedLoss)` with allowedLoss=max.
6. DAI moves from GPv2Settlement to attacker via SwapGuard's allowance.
**Exploitation:** Attacker called SwapGuard.envelope() directly with a single interaction targeting DAI's transferFrom, moving the settlement contract's DAI (covered by its allowance to SwapGuard) to the attacker. No capital or flash loan needed; allowedLoss set to max bypassed loss checks.
**Insight:** Settlement/guard contracts that hold token allowances and expose a generic 'interactions' executor are a direct drain primitive: check who granted the guard an allowance and whether envelope-style functions validate target/selector.

