# Reserve deficit is excluded from borrow-cap and debt-ceiling checks, allowing new borrows above configured risk limits

K2's borrow-cap check ignores reserve deficit from bad-debt burns, letting new borrows push real exposure above configured caps.

- Payout: Contest reward
- Severity: medium
- Program: K2
- Credited: 0xastronatey
- Disclosed: 2026-08-20
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2026-04-k2#m-41
- Library page: https://bugbountylibrary.com/r/c4%3A2026-04-k2%3AM-41
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:liquidation

**Target:** Soroban lending router borrow-cap/debt-ceiling validation
**Root cause:** Bad-debt liquidation burns debt tokens and records the loss in RESERVE_DEFICIT, but validate_borrow_cap_after_interest compares only live debt-token supply plus new borrow against the cap, omitting the tracked deficit.
**Steps:**
1. Configure asset_b with a 900-token borrow cap.
2. Borrower supplies 1,000 asset_a and borrows 800 asset_b (under cap).
3. Crash asset_a price so collateral is exhausted; liquidator triggers liquidation_call, burning remaining debt and recording ~790 asset_b reserve deficit.
4. Second borrower supplies 500 asset_b collateral and calls borrow for 200 asset_b.
5. Cap check sees 0 + 200 <= 900 and passes, though deficit + new debt ≈ 990 > 900.
**How found:** Code review of the liquidation bad-debt path (add_reserve_deficit after burn_scaled) versus the borrow-cap gate, noticing the protocol treats deficit as real exposure in cover_deficit but excludes it from cap accounting.
**Exploitation:** After a bad-debt liquidation zeroes the debt-token supply while leaving a large tracked deficit, any collateralized borrower can open new debt that pushes reserve_deficit + live_debt past the configured borrow cap or debt ceiling, since the sole cap gate is deficit-blind.
**Insight:** When a protocol reclassifies bad debt out of token supply into a separate tracked variable, audit every invariant/limit check that reads total_supply — the reclassified amount is usually omitted, silently widening exposure limits.
