# Debt is not updated when removing margin from a position

Vault.remove_margin checks liquidability using stale total_debt_shares without calling _update_debt, letting traders pull collateral from already-liquidable positions.

- Payout: Contest reward
- Severity: medium
- Program: Unstoppable
- Credited: stopthecap
- Disclosed: 2023-06-21
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-06-unstoppable-judging/issues/9
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-unstoppable%3AM-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:liquidation

**Target:** Margin DEX Vault contract (Vyper) remove_margin / liquidability check
**Root cause:** remove_margin and the liquidability check read total_debt_shares[_debt_token] without first calling _update_debt, so accrued/stale debt is not reflected in the health calculation.
**Steps:**
1. Open a leveraged position with debt in Vault.vy
2. Let debt accrue so the position becomes liquidable but total_debt_shares is stale
3. Call `remove_margin` on the position
4. Liquidability check at Vault.vy#L487 uses stale total_debt_shares and passes
5. Collateral is withdrawn from a position that is actually liquidable
**How found:** Code reading of remove_margin traced the liquidability check call chain (L444 -> L1142 -> L1099 -> L1111 -> L1117) and noticed _update_debt is never invoked, leaving total_debt_shares stale.
**Exploitation:** Trader with an underwater/liquidable position calls remove_margin; because debt shares were never refreshed via _update_debt, the health check passes and collateral is withdrawn, leaving the protocol with bad debt.
**Insight:** In share-based debt accounting, any function gating collateral withdrawal on a health/liquidability check must refresh debt shares first; trace the check's call chain for a missing _update_debt/accrual call.
