# Zero-scaled repay clears debt

Floor-division of tiny repayments to zero scaled units triggers DebtToken dust-cleanup branch, wiping full remaining debt while paying almost nothing.

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

**Target:** KineticRouter::repay / DebtToken::burn_scaled lending pool
**Root cause:** ray_div_down floors amount*RAY/index to 0 for repayments smaller than index/RAY; burn_scaled accepts zero amount_scaled and the new_scaled_debt <= 1 dust-cleanup branch overwrites it with full current_scaled_debt, deleting the debt.
**Steps:**
1. Borrow and repay down until remaining scaled debt equals 1.
2. Wait for borrow index to grow so 1 scaled unit > minimal repayment.
3. Call KineticRouter::repay with underlying amount whose ray_div_down(amount*RAY/index) floors to 0.
4. burn_scaled receives amount_scaled=0, hits new_scaled_debt <= 1 branch, sets amount_scaled = current_scaled_debt and wipes debt.
5. Router transfers only amount_to_repay to pool and ignores burn return tuple, so underpayment undetected.
**How found:** Code review of ray_div_down truncation in utils.rs and tracing how the zero result flows into DebtToken::burn_scaled's dust-cleanup branch and the router's unchecked burn return.
**Exploitation:** Borrower repays down to 1 scaled unit, then submits a dust repayment that floors to zero scaled; the dust-cleanup branch clears the full remaining debt while only the tiny underlying amount is transferred to the pool, leaving the reserve short.
**Escalation:** Repeat across many accounts or reserves with coarse decimals / grown borrow indices to accumulate supplier losses.
**Insight:** When a math helper floors to zero, trace that zero through every downstream branch — dust-cleanup/<=1 special cases can convert a truncation into a full state wipe; also check whether callers validate the effective burn result rather than the requested amount.
