Assessment reports>GTE -- Perp>High findings>The ,isLong, flag for a position is not reset to ,false, during liquidation, preventing users from opening long positions
Category: Coding Mistakes

The isLong flag for a position is not reset to false during liquidation, preventing users from opening long positions

High Severity
High Impact
High Likelihood

Description

During an administrative liquidation, the isLong flag of a position is not reset to false if the amount of that position becomes zero.

function liquidatePosition(Position storage self, uint256 quoteTraded, uint256 baseTraded)
    internal
    returns (PositionLiquidateResult memory result)
{
    // [...]
    if (position.amount == 0) {
        result.close = true;
        delete margin;
    }
    //[...]
}

Following such a liquidation, the account associated with this position may post sell limit orders. If a user then attempts to open a long position, their buy order could match one of these sell limit orders. This match triggers an attempt to update the seller's position by calling the _updatePosition function.

Within the _updatePosition function, if the side parameter is Side.SELL and the position’s isLong flag is true, the _close function is called. The _close function subsequently fails because the position's amount is zero.

function _updatePosition(Position memory self, Side side, uint256 quoteTraded, uint256 baseTraded, uint256 leverage)
    private
    pure
    returns (PositionUpdateResult memory result)
{
    bool openLong = side == Side.BUY && (self.isLong || self.amount == 0);
    bool openShort = side == Side.SELL && !self.isLong; // isLong at default value implies at least open, so no need to check amount

    Position memory position = self;

    if (openLong || openShort) {
        int256 marginDelta = _open(position, side, quoteTraded, baseTraded, leverage, result.oiDelta);
        result.marginDelta = marginDelta;
        result.collateralDelta = marginDelta;
    } else {
        result = _close(position, side, quoteTraded, baseTraded, leverage);
    }
}

Consequently, this issue prevents users from successfully opening certain long positions.

Impact

A malicious actor can exploit this vulnerability to prevent users from opening new long positions by performing the following actions:

  • They can open a long position with the minimum-allowable amount and maximum leverage, then wait for an administrator to liquidate this position when it becomes liquidatable.

  • After the position is liquidated, they can repeatedly post sell limit orders for a minimal amount, targeting the best ask price. Since these orders cannot be filled when matched, this action blocks other users from opening new long positions.

Recommendations

We recommend resetting the isLong flag to false for a position if its amount becomes zero during liquidation.

Remediation

This issue has been acknowledged by Liquid Labs, Inc., and a fix was implemented in commit a969476a.

Zellic © 2025Back to top ↑