# Market: read-only reentrancy inflates collateral, drains $220k

Read-only reentrancy in Market's Beefy vault collateral let attacker inflate collateral price via Curve pool callback, borrow MAI, and liquidate for $220k profit.

- Payout: Real-world hack
- Severity: high
- Program: Market
- Analysis by: DeFiHackLabs
- Disclosed: 2022-10-24
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-10/Market_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20221024-market
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:flash-loan vuln:oracle-manipulation vuln:reentrancy

**Target:** Lending market with Beefy vault collateral and Curve LP oracle
**Root cause:** The protocol's collateral price oracle relied on Curve pool's virtual price, which could be manipulated during a reentrant callback (remove_liquidity triggers receive()) before the pool state was updated, allowing inflated collateral valuation.
**Steps:**
1. Flash loan 15,419,963 WMATIC from Aave and 34,580,036 WMATIC + 19,664,260 stMATIC from Balancer.
2. Add liquidity to WMATIC/stMATIC Curve pool: `vyperContract.add_liquidity([19_664_260 ether, 49_999_999 ether], 0)` minting 34,640,026 stMATIC_f.
3. Enter Market with CErc20_mmooCurvestMATIC_MATIC_4 and deposit 90,000 stMATIC_f into Beefy vault to mint 85,901 mooCurvestMATIC-MATIC, then mint 429,505 Ctokens.
4. Call `vyperContract.remove_liquidity(stMATIC_f.balanceOf(address(this)), [0,0], true)` to burn LP tokens; this triggers `receive()` which borrows 250,000 MAI while collateral price is temporarily inflated.
5. Liquidate own position using 70,420 miMATIC via Liquidator contract, redeeming Beefy vault tokens and removing liquidity again.
6. Sell all miMATIC for WMATIC via router, repay flash loans, and keep profit.
**How found:** Likely identified that Curve pool's remove_liquidity triggers a callback before updating internal state, and that Market's oracle read the pool's virtual price during that window.
**Exploitation:** Attacker used nested flash loans to acquire large WMATIC/stMATIC, added liquidity to Curve to mint LP tokens, deposited into Beefy vault as collateral on Market, then triggered a reentrant callback during remove_liquidity that borrowed MAI against inflated collateral. After the callback, collateral price dropped, allowing self-liquidation to seize the collateral and extract value.
**Escalation:** Chained Aave and Balancer flash loans to amplify capital, then used the reentrancy to borrow and self-liquidate for profit.
**Insight:** When a lending protocol uses a Curve LP token as collateral, check if the oracle reads virtual_price or get_virtual_price during a callback from remove_liquidity; a reentrant borrow can be taken against a temporarily inflated price.

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

**Read-only reentrancy borrow in receive()**

```
receive() external payable {
        //  Borrow MAI with expensive collateral
        // (,uint256 amount,) = unitroller.getAccountLiquidity(address(this));  191
        CErc20Delegate_mMAI_4.borrow(250_000 ether); // 250_000 miMATIC
    }
```

**Curve remove_liquidity triggering reentrancy**

```
vyperContract.remove_liquidity(stMATIC_f.balanceOf(address(this)), [uint256(0), uint256(0)], true); // burn stMATIC_f, trigger receive()
```

**Liquidation call with inflated collateral**

```
miMATIC.approve(address(CErc20Delegate_mMAI_4), type(uint256).max);
        require(
            CErc20Delegate_mMAI_4.liquidateBorrow(main, 70_420 ether, address(CErc20_mmooCurvestMATIC_MATIC_4)) == 0,
```

