# Leverage borrowing with stale rate can atomically create bad debt with no prior positions and no investment

Tapioca leverage buy/borrow/removeCollateral accept stale oracle rates, letting anyone atomically open a leveraged position and withdraw collateral for bad debt when market price dropped >25%.

- Payout: Contest reward
- Severity: medium
- Program: Tapioca
- Credited: hyh
- Disclosed: 2024-02-14
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-tapioca-judging/issues/79
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-17
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:liquidation vuln:oracle-manipulation

**Target:** Tapioca-bar lending markets (BigBang, Singularity, Origins) leverage/borrow/collateral contracts
**Root cause:** updateExchangeRate() falls back to the cached exchangeRate when the oracle returns not-updated, as long as rateTimestamp + rateValidDuration >= block.timestamp. The solvent modifier uses this stale rate for risk-increasing operations (leverage buy, borrow, removeCollateral), so solvency is checked against an outdated price.
**Steps:**
1. Wait until oracle.get() returns updated=false (stale) while the real market price has dropped more than FEE_PRECISION - collateralizationRate (25%).
2. Call `buyCollateral(from, borrowAmount, supplyAmount, data)` on BB or SGL leverage: borrows against stale high rate, buys collateral cheaply from the market.
3. Call `removeCollateral(from, to, share)` (SGL) or Origins removeCollateral to withdraw the extra collateral now valued above the borrowed amount.
4. Repeat atomically in one tx; protocol is left with bad debt equal to the rate mismatch minus the 25% buffer.
**How found:** Code review of the solvent modifier and updateExchangeRate fallback: noticed risk-increasing operations (leverage buy, borrow, removeCollateral) share the same stale-rate-tolerant solvency check, and reasoned that a market price drop beyond the collateralization buffer during oracle staleness lets an attacker open and unwind atomically.
**Exploitation:** Attacker needs no prior position or capital: within one transaction, leverage-buy collateral at the depressed market price while the solvent check uses the stale oracle rate, then remove the surplus collateral. The difference between the stale rate and the real rate (beyond the 25% collateralization buffer) is extracted as protocol principal loss / bad debt.
**Insight:** When an oracle wrapper silently falls back to a cached rate, audit every caller of the solvency/health check: risk-increasing actions (new borrows, leverage, collateral removal) should require a fresh rate, while only risk-reducing actions (repay, liquidate) may tolerate staleness. Compare the staleness window against the collateralization buffer to bound extractable value.
