The recent security incident on the GMX V1 platform is a complex attack utilizing a Cross-Contract Re-entrancy vulnerability, precisely targeting the design flaw in the core Vault contract's price calculation mechanism. The attacker maliciously manipulated the globalShortAveragePrices, a key state variable, by re-entering the opening function during an incomplete closing operation. This manipulation led to a significant deviation in the calculation of the platform's Assets Under Management (AUM), artificially inflating the price of the liquidity provider token GLP. Ultimately, the attacker cashed out by redeeming their GLP at the manipulated high price, resulting in approximately $42 million in funds lost.
1. Core components and related mechanisms
To understand the attack principle, it is essential first to clarify several key technical components of GMX V1:
Vault.sol: The core asset library contract of the protocol. This contract is responsible for holding all liquidity assets and executing all core logic, including trading, position management (opening and closing positions), and the minting and redemption of GLP tokens.
GLP (GMX Liquidity Provider Token): An ERC-20 token representing a share of the protocol's liquidity pool. Its price is strictly determined by the following formula:
GLP Price = Total Assets Under Management (AUM) of the Vault contract / Total Supply of GLP tokens
globalShortAveragePrices: A key state variable within the Vault contract. It records the weighted average opening price of all short positions across the platform. This variable is the basis for calculating the platform's overall floating profit and loss (PnL), thus directly affecting the final value of AUM. Any manipulation of this variable will directly reflect on the price of GLP.
'Checks-Effects-Interactions' (Checks-Effects-Interactions) pattern: A recognized paradigm for secure smart contract development. This pattern requires that when the contract executes a function, it should first complete all internal checks (such as permissions and input validation), then update all affected state variables (effects), and finally interact with external contracts (such as transfers). Violating this pattern creates conditions for re-entrancy attacks.
2. Vulnerability root cause analysis
The occurrence of this attack is rooted in two closely coupled deep vulnerabilities:
Violation of the 'Checks-Effects-Interactions' pattern:
The GMX Vault contract has significant security vulnerabilities in the execution order when processing the closing function (decreasePosition). The contract executes the fund transfer to the target address (an external call) before completing the state update. Specifically, the nonReentrant protection lock is only released after the funds are sent to the target address via a low-level .call(). This provides a time window for the malicious contract receiving the funds to invoke other functions of the protocol before the original function completes.
Design flaw in the globalShortAveragePrices update mechanism:
When processing the logic for increasing short positions (increasePosition), the Vault contract instantaneously and atomically updates the global variable globalShortAveragePrices based on the size and price of the new position. This design is highly risky as it allows a single transaction to have a massive and immediate impact on a critical parameter that determines the entire protocol's valuation, lacking any smoothing or delay mechanisms.
3. Detailed Attack Path
The attacker executed precise, phased operations, with the call path as follows:
Phase One: Preliminary Preparation
The attacker deploys a smart contract containing malicious logic.
The attacker normally uses assets such as WBTC to mint a certain amount of GLP tokens as capital for subsequent arbitrage.
The attacker establishes a small long position, intended solely to trigger the decreasePosition function later.
Phase Two: Core Attack Execution
Trigger entry point: The attacker calls the decreasePosition function, requesting to close their small long position created in the preparation phase.
Re-entry point: After calculating the collateral to be refunded, the Vault.decreasePosition function sends funds to the attacker's malicious contract address via .transfer() or low-level .call(). This is the critical trigger point of the attack.
Executing re-entry: The fund transfer to the malicious contract triggers its pre-set fallback() or receive() function. At this moment, the external Vault.decreasePosition function has not yet completed execution, and its nonReentrant lock is still active.
Executing malicious payload: Within the fallback() function, the attacker initiates an entirely new, independent call chain targeting the increasePosition function, aiming to establish an unusually large WBTC short position.
Bypassing the re-entry lock: Since the new call is initiated from the attack contract, targeting the Router and ultimately reaching the Vault, it creates an entirely new transaction context, thus successfully bypassing the nonReentrant lock set in the decreasePosition function within the Vault contract, allowing the execution of the increasePosition logic.
Manipulating price parameters: The Vault.increasePosition function receives a massive short opening request. According to its design, the contract immediately uses the data from this new position to update globalShortAveragePrices. Due to the enormous size of the new position, it forcibly pulls the average short price of WBTC down from a market fair value (e.g., ~100,1000) to a completely distorted value (e.g.,
100,000) forcibly pulled down to a completely distorted value (for example,
2,000).
Distorting AUM calculation: This manipulated extremely low short average price leads the system to erroneously believe that all short positions on the platform are in significant floating loss when calculating AUM. According to GMX protocol, the trader's loss translates into profits for liquidity providers (GLP holders). Thus, the system counts this enormous, false 'trader loss' into the protocol's AUM.
Completing the re-entry: The fallback() function of the malicious contract finishes executing, control returns to the original Vault.decreasePosition function. This function continues executing the remaining part, ultimately completing the call and releasing the lock.
Phase Three: Profit Extraction
At this point, the on-chain state has been confirmed, and the price of GLP within the GMX protocol has been successfully manipulated to an inflated level.
The attacker immediately called the redemption function (removeLiquidity) to sell their GLP tokens held in the first phase at the manipulated high price, extracting real value assets (WBTC, WETH, USDC, etc.) from the Vault treasury far exceeding their rightful share, completing the attack loop.