# liquidatePositionsPartyB can be used by malicious liquidator to liquidate only select positions which artificially inflates partyA upnl and allows to steal funds

Selective liquidation of only losing partyB positions leaves profitable positions counted in partyA upnl, letting partyA deallocate inflated funds and dump bad debt on partyB.

- Payout: Contest reward
- Severity: high
- Program: Symmetrical
- Credited: panprog
- Disclosed: 2023-06-05
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2023-06-symmetrical-judging/issues/160
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-2
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:high tech:solidity technique:chained vuln:accounting-error vuln:business-logic vuln:liquidation vuln:signature-replay

**Target:** Symmio core liquidation facet (liquidatePartyB / liquidatePositionsPartyB / deallocate)
**Root cause:** PartyA actions (deallocate, close, etc.) remain allowed while one of its partyBs is mid-liquidation, so internal accounting (upnl, allocated balance) is out of sync and can be exploited.
**Steps:**
1. partyA opens a LONG with honest partyB and two opposite LONG/SHORT positions with a controlled partyB2 at minimal allocation, sized so partyB2 becomes liquidatable when price moves.
2. Price drops to 5: partyA is -500 on the honest LONG, +50 on SHORT with partyB2, and partyB2 is liquidatable.
3. Liquidator calls `liquidatePartyB(partyB2, partyA, upnlSig)` which credits partyB2's allocated balance to partyA.
4. Liquidator calls `liquidatePositionsPartyB(partyB2, partyA, quotes=[2], prices=[5])` liquidating only the losing LONG quote, leaving the profitable SHORT active.
5. partyA's upnl now shows artificial profit (+500); partyA calls `deallocate(1009, upnlSig)` draining its full allocated balance.
6. Liquidator finishes with `liquidatePositionsPartyB(..., quotes=[3], ...)`; partyA is left with zero balance and large bad debt, partyB loses its profit.
**How found:** Code reading of the two-step partyB liquidation flow: noticed liquidatePositionsPartyB accepts an arbitrary quote array and that no function blocks partyA actions while a counterparty partyB is mid-liquidation, so upnl/allocated balance are temporarily inconsistent.
**Exploitation:** Attacker controls partyA (and optionally partyB2/liquidator). After liquidatePartyB credits partyB2 funds to partyA, the attacker selectively liquidates only losing quotes so the remaining profitable quotes still count in upnl, then deallocates the inflated balance before liquidation completes. Alternatively, partyA alone can backrun liquidatePartyB / frontrun liquidatePositionsPartyB and reuse a pre-liquidation upnl signature (nonce not incremented) to deallocate double-counted profit.
**Escalation:** Chained with the missing nonce increment in liquidatePartyB (signature replay of stale upnl) and with the muon app counting liquidated quotes, enabling theft of all protocol funds; also usable by a liquidator alone to force liquidation of a solvent partyA for fees.
**Insight:** In two-phase liquidation designs, check whether the counterparty can still act between phase 1 (fund transfer) and phase 2 (position settlement) — any state where a position is both credited and still counted in pnl is a double-count window; also check whether liquidation bumps the nonce used by signed pnl oracles.
