# Platypus Finance: collateral double-count drains ~$8.5M via Treasure

Platypus Treasure collateral check failed to account for emergency-withdrawn LP, letting attacker borrow USP against collateral then withdraw it and swap out ~$8.5M.

- Payout: Real-world hack
- Severity: critical
- Program: - Platypusdefi
- Analysis by: DeFiHackLabs
- Disclosed: 2023-02-17
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-02/Platypus_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230217-platypus
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** Platypus Treasure lending / MasterPlatypus staking on Avalanche
**Root cause:** Treasure.borrow computed borrowLimit from the user's staked LP position, but MasterPlatypus.emergencyWithdraw let the same LP be pulled out after borrowing, so the collateral backing the USP debt was removed while the debt remained.
**Steps:**
1. Flash loan `44_000_000 * 1e6` USDC from Aave V3 via `flashLoanSimple`.
2. `Pool.deposit(USDC, amount, address(this), block.timestamp)` to mint LP-USDC.
3. `Master.deposit(4, LPUSDCAmount)` to stake LP-USDC in MasterPlatypus pid 4.
4. Read `Treasure.positionView(address(this), LPUSDC)` and take `borrowLimitUSP`.
5. `Treasure.borrow(LPUSDC, borrowAmount)` to borrow max USP against the staked LP.
6. `Master.emergencyWithdraw(4)` to pull the LP back out while debt remains.
7. `Pool.withdraw(USDC, LPUSDC.balanceOf(this), 0, this, block.timestamp)` to redeem USDC.
8. Swap borrowed USP to USDC/USDC.e/USDT/USDT.e/BUSD/DAI.e via `Pool.swap` and repay flash loan.
**How found:** Likely spotted that Treasure's borrow limit derives from staked LP while MasterPlatypus exposes emergencyWithdraw that returns the LP without settling Treasure debt, breaking the collateral invariant.
**Exploitation:** Attacker flash-borrowed 44M USDC, deposited into the Platypus USDC pool for LP tokens, staked them in MasterPlatypus, borrowed the full USP borrow limit from Platypus Treasure against that collateral, then used emergencyWithdraw to reclaim the LP and withdraw the underlying USDC. The USP debt was left unbacked; borrowed USP was swapped across the pool's stablecoin pairs to extract value, netting ~$8.5M.
**Escalation:** Chained flash loan + LP staking + Treasure borrow + emergencyWithdraw to convert an unbacked debt into drained pool liquidity across six stablecoin pairs.
**Insight:** When a lending market reads collateral from a separate staking contract, check every exit path on that staking contract (emergencyWithdraw, migrate, unlock) for whether it notifies or blocks the lender; any unstake that bypasses debt settlement is a free borrow.

