A vulnerability exists in the PerpetualVault::_withdraw function, specifically in the calculation of the Profit and Loss (PnL) deduction. The issue arises due to the use of gmxReader.getPositionInfo with an incorrect parameter usePositionSizeAsSizeDeltaUsd set to true that results in the PnL being calculated for the entire position rather than just for the user's share. This leads to an excessive deduction from the user's withdrawal amount, reducing their funds unfairly.
The affected code is in the PerpetualVault::_withdraw function, specifically the part:
The function vaultReader.getPnl:
internally calls gmxReader.getPositionInfo with the last parameter usePositionSizeAsSizeDeltaUsd set to true.
This setting computes the PnL for the entire position rather than just for sizeDeltaUsd.
As a result, pnl in PerpetualVault::_withdraw represents the total loss of the entire position instead of only the user's portion.
This incorrect calculation leads to an unfair reduction in the user's withdrawal amount (collateralDeltaAmount is less than it should be).
Users may receive significantly less funds than they actually hold when withdrawing.
A key invariant of the protocol, Depositor Share Value Preservation, is broken. Losses may not be distributed proportionally based on share ownership.
This issue can cause financial losses and unfair withdrawals.
Example:
Assume:
User A has 20 shares
User B has 20 shares (same as user A)
totalShares = 100
collateralAmount = 20,000
pnl = -$500 (the total PnL for the position)
shortTokenPrice.max = 1
User A Withdraws First (While Position is Still Open)
Using the calculation in PerpetualVault::_withdraw, User A’s collateralDeltaAmount is (ignoring feeAmount):
What they should actually get (when pnl is scaled properly to their share proportion):
Discrepancy: 400 loss for User A
User B Withdraws After the Position Closes
After User A withdraws:
collateralAmount updates to (Subtracting User A’s collateral and pnl ):
Now User B withdraws their share of the remaining collateral following PerpetualVault::_withdraw for a closed position:
Final Discrepancy
**User A received: 3,500 **
**User B received: 4,000 **
Difference: 500
Because the loss was not distributed proportionally, User A lost 400 more than they should have, while User B benefited by receiving a higher amount than they should.
In addition, since the whole position pnl is subtracted in
collateralDeltaAmount may become negative causing the function to revert.
Manual Review
Two possible ways of mitigating the vulnerability are:
Modify gmxReader.getPositionInfo Call
Set the last parameter to false when calling gmxReader.getPositionInfo inside vaultReader.getPnl.
Scale PnL Deduction in _withdraw Function
Adjust pnl by multiplying it with shares / totalShares before deducting from collateralDeltaAmount.
Likelihood: Medium/High, every withdrawal from a short or leveraged vault that is not liquidated and has a negative PnL. Impact: High, subtract collateralDeltaAmount from the entire PnL of the position instead of the delta amount PnL. DoS or loss of funds
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.