# When code defaults on remaining liability, it does not delete remaining auction, which is problematic if the user has called fill with a % less than 100

Partial fill of a Blend bad-debt auction defaults backstop liability but leaves the remaining auction stored, letting a later filler take backstop tokens with zero debt.

- Payout: Contest reward
- Severity: medium
- Program: Blend
- Credited: rscodes
- Disclosed: 2025-08-13
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-02-blend-v2-audit-certora-formal-verification#m-09
- Library page: https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AM-09
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:rust tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Soroban pool bad_debt_auction.rs fill_bad_debt_auction / auction.rs fill
**Root cause:** fill_bad_debt_auction defaults remaining backstop liabilities when below the 5% threshold but the caller still stores the leftover remaining_auction, so the auction persists with no matching liability.
**Steps:**
1. Call `fill` on a BadDebtAuction with `percent_filled = 50`, so `scale_auction` splits into to_fill and remaining_auction.
2. `fill_bad_debt_auction` runs; backstop threshold < 0_0000003 triggers `default_liabilities` on remaining backstop liabilities.
3. Caller stores `remaining_auction` via `storage::set_auction` instead of deleting it.
4. Before block 400 the bid token is non-zero; any fill panics in `backstop_state.rm_positions` because liability was already defaulted.
5. At block 400+ bid token is zero; filler calls `fill` and receives lot (backstop tokens) with no debt taken on.
**How found:** Code reading: noticed `default_liabilities` in `fill_bad_debt_auction` but that `fill` still persists `remaining_auction` when `percent_filled < 100`, then traced the auction decay curve to find the window where bid is zero but lot is still paid.
**Exploitation:** Attacker waits until the auction's bid token decays to zero (block 400+), then fills the stale remaining bad-debt auction, receiving backstop lot tokens for free while taking on no debt, at the expense of backstop stakers.
**Insight:** When a partial-fill path splits state into to_fill/remaining, check every branch that mutates or deletes the underlying liability—if the mutation isn't mirrored on the stored remainder, the leftover auction becomes a free payout once its bid side decays to zero.
