# SecuredFi: same-block self-trade inflates collateral price, drains WBTC

SecuredFi's getMarketUnitPrice averaged same-block fills, so a flash-loan-funded cross-account self-trade at par inflated cheap lend positions into full collateral, draining ~0.9 WBTC.

- Payout: Real-world hack
- Severity: high
- Program: SecuredFi
- Disclosed: 2026-09-05
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-09/SecuredFi_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260905-securedfi
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** LendingMarketController / TokenVault order-book price oracle
**Root cause:** getMarketUnitPrice computes blockTotalAmount*10000/blockTotalFutureValue over fills in the current block with no time-weighting; isReliableBlock flips true once a per-block volume gate is met, which flash-loan-funded self-trades trivially clear. The collateral path reads with isReadOnly=true, always taking the manipulated same-block ratio.
**Steps:**
1. Flash-borrow WBTC from Balancer V2 Vault (fee-free)
2. From maker account: `deposit(WBTC_CCY, amount)` then `executeOrder(WBTC_CCY, MATURITY, 0 /*LEND*/, amount, 10000)` at par
3. From main account: `executeOrder(WBTC_CCY, MATURITY, 1 /*BORROW*/, amount, 10000)` matching the maker leg, booking a fill at par and setting isReliableBlock=true
4. Post a cheap lend position at unitPrice=3 on the main account; getMarketUnitPrice now returns 10000, valuing it as fully-backed collateral
5. `withdraw(WBTC_CCY, amount)` from TokenVault against the fake collateral, draining ~0.9 WBTC
6. Repay Balancer flash loan, keep net WBTC profit
**How found:** Code review of verified OrderBookLib source revealed getMarketUnitPrice uses same-block blockTotalAmount/blockTotalFutureValue with only a volume gate (isReliableBlock) and no time-weighting; the collateral path reads isReadOnly=true, so the same-block ratio is always trusted. The per-block volume gate is clearable via flash-loan-funded self-trades.
**Exploitation:** Attacker flash-loans WBTC, uses two accounts to self-match LEND/BORROW orders at par within one block, inflating getMarketUnitPrice to 10000. A cheap lend position is then treated as fully-backed collateral, letting the attacker withdraw the pool's real WBTC. Net ~0.9 WBTC (~$72K) per drain; ~$104K total across copycat bots.
**Escalation:** Public bug replayed by MEV searcher 'coffeebabe' and multiple copycat bots, each draining separately; total ~$104K across all actors.
**Insight:** When a price oracle averages fills within the current block and gates reliability on volume alone, check whether an attacker can supply both sides of a fill in one block (cross-account self-trade) to set the ratio arbitrarily; also check whether the collateral read path forces the same-block branch (isReadOnly=true) rather than a time-weighted history.
