# Polynomial Zap: unvalidated swapTarget drains user approvals

Polynomial's swapAndDeposit lacked input validation on swapTarget/swapData, letting an attacker pass transferFrom calldata to drain victims' USDC approvals.

- Payout: Real-world hack
- Severity: high
- Program: - Polynomial
- Analysis by: DeFiHackLabs
- Disclosed: 2022-11-18
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-11/Polynomial_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20221118-polynomial
- 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:** PolynomialZap swapAndDeposit on Optimism
**Root cause:** swapAndDeposit accepted an arbitrary swapTarget and swapData without validating that the target was a legitimate swap router or that calldata matched the intended swap, so attacker-supplied calldata was executed with the zap contract as msg.sender.
**Steps:**
1. Identify victims with USDC approvals to the Polynomial zap contracts (0xDEEB...4281, 0xB162...7c82).
2. Build calldata `abi.encodeWithSelector(0x23b872dd, victim, attacker, amount)` (transferFrom).
3. Call `swapAndDeposit(victim, ETH_ADDRESS, attacker, USDC, attacker, 0, data)` on the zap contract.
4. Zap executes the attacker calldata as swapTarget, pulling victim USDC via existing allowance to the attacker.
5. Repeat for each victim; collect USDC.
**Exploitation:** Attacker looped over five victims, calling swapAndDeposit with swapTarget=USDC and swapData=transferFrom(victim, attacker, amount), abusing each victim's standing USDC allowance to the zap contract to transfer funds directly to the attacker.
**Insight:** Zap/router contracts that take a user-supplied swapTarget plus arbitrary calldata are effectively a generic call primitive: any token approval to the zap becomes drainable by crafting transferFrom calldata, so check whether swapTarget is whitelisted and whether calldata selector is constrained.

