# Zapper Arbitrary Call Data Bugfix Review

Zapper's ZapOut permit functions accepted arbitrary calldata, letting an attacker call transferFrom on a victim's approved LP tokens and steal them.

- Payout: $25,000
- Severity: critical
- Program: Zapper
- Credited: Lucash-dev
- Disclosed: 2021-06-17
- Write-up quality: 7/10
- Original: https://immunefi.com/blog/bug-fix-reviews/zapper-arbitrary-call-data-bugfix-review/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-zapper-arbitrary-call-data-bugfix-review
- Tags: domain:web3 impact:funds-loss kind:bounty platform:blog platform:immunefi sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** Uniswap/Sushiswap ZapOut contracts (ZapOutWithPermit, ZapOut2PairTokenWithPermit)
**Root cause:** ZapOut permit functions forwarded user-supplied arbitrary calldata to an arbitrary pool contract without validating the selector or arguments, so the contract itself executed transferFrom against the victim's approval.
**Steps:**
1. Victim approves Zapper ZapOut contract to spend their LP tokens (normal expected flow).
2. Attacker ABI-encodes `transferFrom(victim, attacker, victimBalance)` via `PAIR.interface.encodeFunctionData`.
3. Attacker calls `ZapOut2PairTokenWithPermit(PAIR, victimBalance, PAIR, data)` on `0xfb13b2ae7282cfaca2c0cf62d9aed131db2209f7`.
4. Zapper executes the injected call, moving victim LP tokens to attacker, then removes liquidity and returns underlying tokens to attacker.
**How found:** Researcher read the ZapOut permit functions and noticed user-supplied calldata was passed to an arbitrary pool with no selector/argument validation, hypothesizing transferFrom could be smuggled in.
**Exploitation:** Attacker scans all addresses that have approved the Zapper ZapOut contract, encodes transferFrom calldata targeting a victim's LP balance, and passes it as the permitData argument. Zapper treats it as approval data, executes the transferFrom from its own address (which holds the victim's allowance), then proceeds to remove liquidity and hands underlying tokens to the attacker. Attacker must first approve the ZapOut contract for their own (zero) balance to satisfy the flow.
**Escalation:** Repeatable against every user who ever approved the contract, enabling ongoing theft of LP tokens at scale.
**Insight:** In DeFi aggregator/zapper contracts, any function taking user-supplied calldata plus an arbitrary target is a candidate for smuggling transferFrom/approve against the contract's own allowances; grep for low-level .call with user data.
