# User fund loss because function purchaseLiquidationAuctionNFT() takes extra liquidation penalty when user's last collateral is liquidated, (set wrong value for maxDebtCached when isLastCollateral is true)

purchaseLiquidationAuctionNFT sets maxDebtCached to full debt when liquidating last collateral, so the 10% penalty is taken from the entire auction price instead of only the excess, shorting the borrower.

- Payout: Contest reward
- Severity: medium
- Program: Backed Protocol
- Credited: unforgiven
- Disclosed: 2023-01-31
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-backed-findings/issues/255
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-backed%3AM-08
- 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:** purchaseLiquidationAuctionNFT liquidation auction function
**Root cause:** When isLastCollateral is true, maxDebtCached is set to debtCached instead of 0, making neededToSaveVault 0 and treating the whole auction price as excess subject to the liquidation penalty.
**Steps:**
1. Borrower has debt 900, single NFT collateral, auction price 1000.
2. Liquidator calls `purchaseLiquidationAuctionNFT(auction, maxPrice, sendTo, oracleInfo)` paying 1000 papr.
3. collateralValueCached == 0 so isLastCollateral = true; maxDebtCached = debtCached = 900.
4. neededToSaveVault = 0; excess = price = 1000.
5. _handleExcess takes 10% penalty on 1000 = 100 instead of on (1000-900) = 10.
6. Borrower receives 0 instead of the 90 they should get.
**How found:** Code reading of purchaseLiquidationAuctionNFT: noticed maxDebtCached is set to debtCached when isLastCollateral, which zeroes neededToSaveVault and makes all paid papr count as excess.
**Exploitation:** Liquidator purchases the auction; the contract miscomputes excess and applies the 10% liquidation penalty to the full price, diverting the borrower's surplus to the protocol.
**Insight:** In liquidation math, check the isLastCollateral / zero-collateral branch separately: setting maxDebt to current debt instead of 0 makes the entire payment look like excess, so penalty and surplus accounting diverge from intent.
