# SushiSwap RouteProcessor2: unchecked route enables callback spoofing and approval drain

SushiSwap RouteProcessor2 failed to validate user-supplied route, letting attacker spoof a Uniswap V3 pool callback and drain approvals from a victim, stealing >$3.3M.

- Payout: Real-world hack
- Severity: critical
- Program: SushiSwap
- Analysis by: DeFiHackLabs
- Disclosed: 2023-04-09
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-04/Sushi_Router_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230409-sushi-router
- Tags: area:web3 domain:web3 impact:data-leak impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** RouteProcessor2 contract (processRoute / uniswapV3SwapCallback)
**Root cause:** processRoute trusts the user-supplied `route` bytes, including an arbitrary pool address, and later invokes uniswapV3SwapCallback without verifying the caller is a legitimate Uniswap V3 pool. An attacker can set the pool to their own contract, which then calls the callback with crafted data to transferFrom a victim's approved tokens.
**Steps:**
1. Victim has approved RouteProcessor2 to spend LINK (or other tokens).
2. Attacker crafts a route: `commandCode=1, tokenIn=LINK, num=1, share=0, poolType=1, pool=attackerContract, zeroForOne=0, recipient=0`.
3. Attacker calls `processRoute(native, 0, native, 0, address(0), route)`.
4. RouteProcessor2 calls `swap` on the attacker-controlled pool (the `pool` field).
5. Attacker's `swap` implementation calls `processor.uniswapV3SwapCallback(100e18, 0, abi.encode(WETH, victim))`.
6. RouteProcessor2's callback decodes `(token, from)` from `data` and executes `token.transferFrom(from, msg.sender, amount)` — draining the victim's approved LINK to the attacker.
**How found:** Likely spotted that the `route` parameter includes an arbitrary pool address and that the callback does not verify msg.sender against a registry of legitimate pools. The attacker realized they could impersonate a Uniswap V3 pool and feed arbitrary `data` to the callback, which decodes a `from` address and calls transferFrom.
**Exploitation:** Attacker needs a victim who has granted token approval to RouteProcessor2. By supplying a malicious `pool` address in the route, the attacker's contract is called by processRoute, which then invokes uniswapV3SwapCallback on RouteProcessor2. The callback trusts the `data` argument and performs transferFrom from the victim to the attacker. No capital or flash loan required; only gas. Over $3.3M was stolen from multiple victims.
**Escalation:** The same primitive can be repeated for any token a victim has approved to RouteProcessor2, and can be automated to sweep all approvals.
**Insight:** When a router accepts a user-supplied pool address and later calls a callback that trusts caller-supplied data, check whether the callback verifies msg.sender. If not, you can spoof the pool and make the router pull tokens from any address that approved it.

## Proof of concept (copied exactly from the original report)

**Malicious route encoding attacker-controlled pool**

```
uint8 commandCode = 1;
        uint8 num = 1;
        uint16 share = 0;
        uint8 poolType = 1;
        address pool = address(this);
        uint8 zeroForOne = 0;
        address recipient = address(0);
        bytes memory route =
            abi.encodePacked(commandCode, address(LINK), num, share, poolType, pool, zeroForOne, recipient);
```

**processRoute call with crafted route**

```
processor.processRoute(
            0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, //native token
            0,
            0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,
            0,
            0x0000000000000000000000000000000000000000,
            route
        );
```

