# Margin Balance can be forced to be < 0 even realizing upnl indirectly

GTE perps lets a user withdraw all margin while in profit, then close another position to refund marginDelta as fresh collateral, draining funds.

- Payout: Contest reward
- Severity: medium
- Program: GTE
- Credited: dan__vinci
- Disclosed: 2026-02-05
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-08-gte-perps-and-launchpad#m-14
- Library page: https://bugbountylibrary.com/r/c4%3A2025-08-gte-perps-and-launchpad%3AM-14
- 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:** Perps ClearingHouse removeMargin and position close flow
**Root cause:** assertPostWithdrawalMarginRequired allows margin to reach 0 when margin+upnl covers intendedMargin, but close's rebalanceClose refunds marginDelta proportional to closedOpenNotional/leverage without checking whether that IM was already withdrawn.
**Steps:**
1. Open multiple positions with margin; ensure one position has large upnl so equity >= intendedMargin.
2. Call `removeMargin(account, subaccount, amount)` withdrawing entire posted margin; assertPostWithdrawalMarginRequired passes since margin+upnl >= intendedMargin.
3. Close or partially close another position; `_close` computes `result.marginDelta = -closedOpenNotional/leverage` and rebalanceClose returns it as finalMarginDelta.
4. Withdraw the newly credited marginDelta as free collateral.
5. Repeat to extract more than deposited.
**How found:** Code review of removeMargin's margin assertion versus _close/rebalanceClose marginDelta refund logic; noticed refund is computed from closedOpenNotional/leverage regardless of prior withdrawal.
**Exploitation:** Attacker with profitable upnl withdraws full margin, then closes positions to receive marginDelta refunds as free collateral and withdraws them, extracting collateral not actually reserved.
**Escalation:** Replayable loop: withdraw margin, close positions for refunds, withdraw refunds, repeat.
**Insight:** When a protocol separates margin-withdrawal checks from position-close refund accounting, test whether the same initial-margin slice can be refunded after it was already withdrawn; compare the refund formula against the reserved-IM bookkeeping.
