#4 GMX Incident: Cross-Contract Reentrancy Bypasses a Four-Year-Old Guard

#4 GMX Incident: Cross-Contract Reentrancy Bypasses a Four-Year-Old Guard

On July 9, 2025, the decentralized perpetual platform GMX experienced an exploit [1, 2] targeting their V1 contract on the Arbitrum network, resulting in a loss of approximately $42 million. The attacker exploited a cross-contract reentrancy vulnerability to manipulate the GLP price, then used the distorted price to siphon underlying assets from GMX V1's liquidity pools.

Background

GMX V1 [3] is a decentralized perpetuals trading platform deployed on Arbitrum. It allows users to trade perpetual contracts on multiple crypto assets with leverage in a permissionless and non-custodial manner. GMX V1 follows a single multi-asset pool design, where liquidity for all supported assets is aggregated into a unified Vault system.

Position Management in GMX

The position management in GMX is a two-step process. Specifically, users create increase/decrease orders via interacting with the contracts OrderBook or PositionRouter. Then, the authorized keeper account executes users' orders, which updates the global short data in the contract ShortTracker and the corresponding state of the contract Vault. The following two figures demonstrate the two execution paths (the orderbook-execution and router-execution paths) for managing positions in GMX. In this incident, the attacker used both paths to manipulate the global short data and realize profits.

The Orderbook-execution Path

The Router-execution Path

GMX Vault

The contract Vault in GMX is responsible for managing users' positions and assets (e.g., finalizing the profit and loss). To avoid malicious interactions, the contract Vault is only accessible when the "leverage window" is opened (i.e., the variable isLeverageEnabled in the contract Vault is set to true via the function Timelock.enableLeverage()). This validation enforces that order execution must follow the fixed paths (orderbook-execution and router-execution).

GMX Short Tracker

The contract ShortTracker is responsible for tracking and updating the global short data (e.g., the variable globalShortAveragePrice) during the order execution. According to the orderbook-execution and router-execution paths, the function updateGlobalShortData() of the contract ShortTracker is invoked before executing users' orders to sync the latest global short data. This step ensures correct profit and loss realization for users' positions.

Decreasing WETH Position

Different from other orders, decreasing the WETH position via the orderbook-execution path will invoke the function _transferOutETH() in the contract OrderBook to withdraw WETH tokens and transfer the native ETH tokens to users. If the recipient _receiver is a contract, sendValue() could trigger the contract's fallback() function, introducing a potential reentrancy vulnerability. In this incident, the attacker repeatedly exploited this reentrancy vulnerability to extract significant profits.

GLP Token

The GLP (GMX Liquidity Provider) token represents the unified shares for various assets in the contract Vault. Users are allowed to provide and redeem assets by minting and burning GLPs.

The GLP price could be calculated in the following equations:

GLPPrice=AUMGLPTotalSupply\text{GLPPrice}= \frac{\text{AUM}}{\text{GLPTotalSupply}}

AUM=i=asset[0]assets(ΔGlobalShort[i]+AUMOther[i])\text{AUM} = \sum^{assets}_{i = asset[0]}(\Delta_{\text{GlobalShort[i]}} + \text{AUM}_{\text{Other[i]}})

ΔGlobalShort[i]=globalShortSize×(AssetMarketPriceglobalShortAveragePrice)globalShortAveragePrice\Delta_{\text{GlobalShort[i]}} = \frac{ \text{globalShortSize} \times (\text{AssetMarketPrice} - \text{globalShortAveragePrice} ) }{ \text{globalShortAveragePrice} }

Where:

  • GLPTotalSupply represents the total supply of the GLP tokens.
  • AUM consists of the following two components.
    • ΔGlobalShort\Delta_{\text{GlobalShort}} represents the uPnL (i.e., unrealized Profit and Loss) of all short positions.
    • AUMOther\text{AUM}_{\text{Other}} represents the provided liquidity of the LP plus the unrealized uPnL of all long positions. This term remained nearly unchanged throughout the incident prior to profit realization.
  • AssetMarketPrice is the market price (in USD) of the underlying asset.
  • globalShortSize is the sum (in USD) of all short positions.
  • globalShortAveragePrice is the average entry price of the aggregated global short position.

In this incident, the attacker skewed globalShortAveragePrice to manipulate the GLP price and extract profits.

Vulnerability Analysis

The root cause is a cross-contract reentrancy vulnerability in the contract OrderBook. As described in Background, decreasing WETH positions via the orderbook-execution path triggers a low-level fallback call to the receiver through _transferOutETH(). The function carries a nonReentrant modifier, but this guard only prevents reentrancy within the OrderBook contract itself, not cross-contract calls to the Vault.

Under normal operation, the Vault's increasePosition() can only be called through PositionRouter and PositionManager, which invoke ShortTracker to update globalShortAveragePrice before each position change. The attacker created orders with a malicious contract as the receiver, and during the fallback call, directly called increasePosition() on the Vault, bypassing PositionRouter/PositionManager and the associated ShortTracker update. By repeatedly opening and closing short positions without updating globalShortAveragePrice, the attacker progressively skewed the variable. The distorted value inflated the GLP price, allowing the attacker to extract profits by minting and redeeming GLPs.

Attack Analysis

The attacker launched a series of transactions manipulating the global short data and realizing the profit. Specifically, this incident could be divided into three phases: Preparation, Price Manipulation, and Profit Realization. All related transactions are listed in the following table.

Tx No. Phase Description Transaction Time (UTC)
1 Preparation Deploy the attack contract 0xa4ece5...8cd4c93f Jul-09-2025 12:16:32 PM
2 Create an increase WETH-long order 0x0b8cd6...e90a4712 Jul-09-2025 12:22:28 PM
3 Execute the increase WETH-long order 0x28a000...7bf0beef Jul-09-2025 12:23:23 PM
4 Create a decrease WETH-long order 0x20abfe...decc49af Jul-09-2025 12:24:56 PM
5 Price Manipulation 1 Execute the decrease WETH-long order 0x1f00da...6a4a7353 Jul-09-2025 12:25:37 PM
6 Execute the decrease WBTC-short order 0x222cda…c994464e Jul-09-2025 12:25:43 PM
7 Price Manipulation 2 Same as tx 5 0xc9a469...221293c2 Jul-09-2025 12:26:25 PM
8 Same as tx 6 0x1cbf25...d853943a Jul-09-2025 12:26:30 PM
9 Price Manipulation 3 Same as tx 5 0xb58415...3b4cfb0b Jul-09-2025 12:27:22 PM
10 Same as tx 6 0x5a37ff...cb59c3b7 Jul-09-2025 12:27:28 PM
11 Price Manipulation 4 Same as tx 5 0xff6fe6...377bf108 Jul-09-2025 12:28:13 PM
12 Same as tx 6 0xbd65d6...e0187be6 Jul-09-2025 12:28:18 PM
13 Price Manipulation 5 Same as tx 5 0x105273...19fcdec6 Jul-09-2025 12:29:12 PM
14 Same as tx 6 0x0cdbac...84339fcc Jul-09-2025 12:29:17 PM
15 Profit Realization Realize profits 0x03182d....a32626ef Jul-09-2025 12:30:11 PM
16 Refunding Message the attacker 0x92a39e...89547380 Jul-09-2025 02:04:19 PM
17 Response to the GMX protocol 0x1d806c...919feac0 Jul-11-2025 06:29:00 AM
18 Response to the attacker 0x9c4ca9...39fa27fc Jul-11-2025 07:42:17 AM
19 Refund 0x62b845...99211841 Jul-11-2025 08:04:34 AM
20 Refund 0x255d0a...9321b3 Jul-11-2025 08:08:27 AM
21 Refund 0xceafc3...a6313b22 Jul-11-2025 10:17:23 AM

Preparation Phase

  1. (Tx 1) The attacker deployed the attack contract, which is used as the asset receiver during the order execution. The attack contract contained a malicious fallback() function.

  2. (Tx 2) The attacker created an increase WETH-long order for the attack contract in the contract OrderBook.

  3. (Tx 3) A Keeper executed the attacker's increase order (created in step 2), which opened a WETH-long position for the attack contract. (Tx 3).

  4. (Tx 4) The attacker created a decrease WETH-long order for the attack contract in the contract OrderBook.

Manipulation Phase

  1. (Tx 5) A Keeper executed the attack contract's decrease WETH-long order (created in step 4) via the orderbook-execution path. The execution path invoked _transferOutETH(), triggering the malicious fallback() function in the attack contract.

    Since fallback() was invoked during the "leverage window", the attack contract directly interacted with the contract Vault to open a WBTC-short position (via increasePosition()) without updating globalShortAveragePrice, and subsequently created a decrease/close WBTC-short order.

  2. (Tx 6) A Keeper executed the decrease WBTC-short order (created in step 5) via the router-execution path. The execution also created a decrease WETH-long order via the fallback mechanism in the contract PositionRouter.

    Since the WBTC-short position was opened without updating globalShortAveragePrice, closing the position while updating the variable caused an unexpected drop in globalShortAveragePrice.

  3. (Tx 7-14) The attacker repeated steps 5-6 four times. As a result, globalShortAveragePrice was skewed from 1.08e35 to 1.9e33.

Profit Realization Phase

  1. (Tx 15) A Keeper executed the decrease WETH-long order (created in Tx 14) via the orderbook-execution path. This execution triggered the profit realization logic in the attack contract due to the reentrancy vulnerability in the contract OrderBook.

    1. In the fallback invocation, the attack contract first borrowed a flash loan of 7,538,567e18 USDC.

    2. The attack contract invoked mintAndStakeGlp() to mint 4,129,578e18 GLPs using 6,000,000e18 USDC.

    3. The attack contract invoked Vault.increasePosition() to open a WBTC-short position with the remaining 1,538,567e18 USDC. Because WBTC's global short data was extremely skewed, the order execution significantly amplified AUM, sharply increasing the GLP price.

    4. The attack contract invoked unstakeAndRedeemGlp() to redeem GLPs at the amplified price for multiple assets in the contract Vault.

    5. The attack contract invoked Vault.decreasePosition() to close the WBTC-short position.

    6. The attack contract repeated steps 8.b-8.e four times to drain all assets in the contract Vault.

    7. The attack contract repaid the flash loan with a profit of nearly $42 million.

Refunding

Through negotiations with the attacker (Tx 16-18), the attacker ultimately accepted a 10% bounty and returned the remaining stolen assets (Tx 19-21).

Summary

This incident involved a multi-phase exploit against GMX V1 on Arbitrum, resulting in an estimated loss of $42 million. The attacker abused a reentrancy vulnerability on the contract OrderBook to skew the variable globalShortAveragePrice, inflating the GLP price. By leveraging the manipulated price, the attacker siphoned a significant amount of assets.

Key lessons:

  • Cross-contract reentrancy: A nonReentrant modifier on a single contract does not prevent reentrancy into other contracts within the same system. Access control mechanisms that rely on a temporary flag (e.g., the "leverage window") can be bypassed when an external call occurs before the flag is reset.
  • Operational Security: This attacker exploited the protocol in three distinct phases, executing a total of 15 transactions. This incident underscores the critical need for real-time monitoring, prompt alerts, and effective mitigation playbooks.

Reference

  1. https://x.com/GMX_IO/status/1942955807756165574
  2. https://x.com/GMX_IO/status/1943336664102756471
  3. GMX V1

About BlockSec

BlockSec is a full-stack blockchain security and crypto compliance provider. We build products and services that help customers to perform code audit (including smart contracts, blockchain and wallets), intercept attacks in real time, analyze incidents, trace illicit funds, and meet AML/CFT obligations, across the full lifecycle of protocols and platforms.

BlockSec has published multiple blockchain security papers in prestigious conferences, reported several zero-day attacks of DeFi applications, blocked multiple hacks to rescue more than 20 million dollars, and secured billions of cryptocurrencies.

Sign up for the latest updates