PerpetualVault contract's leverage invariant can be violated allowing positions to exceed the maximum leverage of 10000 (BASIS_POINTS_DIVISOR). This breaks a core safety mechanism designed to prevent over-leveraged positions and could lead to increased liquidation risks. Looking at the contract interactions, we can see that leverage values are managed through the PerpetualVault contract while actual position creation happens via GmxProxy.
This leverage calculation here is doesn't account for various factors that affect the final position size when executed by GMX's keepers.
The path involves:
PerpetualVault's position management functions
GmxProxy's order creation and execution
VaultReader's position calculations
The leverage boundary check is meant to prevent users from taking positions with leverage higher than 10000 (100%). However, the current implementation allows this invariant to be broken through specific interaction patterns with GMX's position management system.
The VaultReader contract calculates position sizes and leverage, while GmxProxy executes the actual trades. The missing or insufficient validation in position creation allows leverage to exceed the intended maximum.
When this invariant is violated, positions can be created with leverage exceeding 100%, which:
Increases liquidation risks
Violates core protocol safety assumptions
Could lead to unexpected behavior in position management functions
The issue lies in insufficient leverage validation during position creation and management.
The Perpetual Vault protocol manages leveraged positions with a critical safety invariant, no position should exceed the BASIS_POINTS_DIVISOR (10,000) leverage limit. However, I've discovered a path where this boundary can be breached. In PerpetualVault.sol where positions are managed through a series of asynchronous actions. The leverage check is implemented as an invariant:
The error lies in the interaction between PerpetualVault and GmxProxy during position creation. When creating an increase position order through GmxProxy, the size delta calculation in _createIncreasePosition() function uses
This calculation can result in positions with effective leverage exceeding the intended maximum of 3x (30,000 basis points) due to price impact and fee calculations not being properly accounted for in the leverage validation.
Just like a margin trading account where the broker's risk limits can be circumvented. The protocol intends to limit leverage to 3x, but through this vulnerability, positions can be opened with higher effective leverage. This means:
Users could face unexpected liquidations
The vault's risk parameters are compromised
The core invariant of "consistent leverage per vault" is broken
In the interaction between three key components:
PerpetualVault's leverage parameter (set at initialization)
GmxProxy's order creation logic
VaultReader's position size calculations
The VaultReader contract calculates actual position sizes and leverage, but these calculations happen after the position is already opened through GMX. This creates a gap where the leverage check can be bypassed.
The error lies in how leverage is managed across the protocol's position lifecycle. Like a car's speed governor that's supposed to prevent exceeding a set speed limit, but fails to account for downhill momentum.
In the PerpetualVault system, users deposit USDC to gain exposure to leveraged positions through GMX perpetuals. Each vault represents a specific market with a fixed leverage - 1x, 2x, or 3x ETH vaults. The protocol promises that "leverage will stay consistent from start to finish," but this promise can be broken.
See how the position creation flows through multiple contracts:
The leverage calculation in GmxProxy looks deceptively simple
This means that a 3x ETH vault (leverage = 30000) should never exceed that multiplier. However, the actual position size on GMX can end up larger due to price impact and funding rates not being properly accounted for in the initial calculation.
For traders using these vaults, this creates unexpected risk. A position they believe is 3x leveraged could effectively become 3.5x or higher, increasing liquidation risk. This directly impacts users who chose specific vaults based on their risk tolerance.
Manual
Ensure that leverage never exceeds BASIS_POINTS_DIVISOR under any circumstances, maintaining the core safety invariant of the protocol.
We implement multiple validation layers using VaultReader to get accurate position data and calculates true effective leverage including all GMX-specific factors before allowing position creation.
There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.
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.