Protect Your Project Today
Strengthen your project with the largest web3 security provider.
A CertiK security expert will review your request and follow up shortly.

GMX Incident Analysis

Reports ·Incident Analysis ·
GMX Incident Analysis

Incident Summary

On 9 July 2025, GMX V1 vault was exploited by a white-hat for ~$42M due to a reentrancy issue. The funds were later returned to GMX who awarded the white-hat a 10% bounty. gmx1 The whitehat had minted and then staked GLP before creating a short position directly from the vault contract through reentrancy. Executing in this order bypassed the ShortsTracker, and prevented the average short position price from being updated. This occurs when the market price exceeds the tracked average price, resulting in the protocol overestimating unrealized losses. As a result, the Assets Under Management (AUM) calculation was manipulated to inflate the apparent value of GLP.

Two days after the incident, the white-hat sent an on-chain message to say funds will be returned, then later transferred ~$37M to GMX. gmx2

Background

GMX is a decentralized spot and perpetual exchange that supports low swap fees and low price impact trades. The liquidity for trades comes from LPs who deposit these and other tokens into a single Vault contract. In return, they are given the GLP token, which can be redeemed at any time.

In 2022 GMX, who had a TVL (Total Value Locked) exceeding $500 million, awarded a million-dollar bug bounty to Collider's research arm (https://www.collider.vc/post/gmx-granted-million-dollar-bug-bounty-to-collider-the-bug-aftermath).

Prior to the bounty award, users placed orders for their positions, and GMX off-chain keepers executed the order as follows:

image

Updates of short sized and average global short price of user-declared indexToken used to both be in the Vault contract at the lower level of execution.

After the major vulnerability was found in the bug bounty, changes were made so that the updates were handled by a newly introduced ShortTracker called by the higher-level PositionManager contract:

image

This update, or what’s left behind, introduced an unexpected vulnerability that led to ~$42M loss.

Vulnerability

During the AUM (asset under management) calculation by GlpManager, which is critical in determining the value of a user’s holding, the size is still fetched from the Vault. gmx5 As shown in the “legacy” code in Vault.IncreasePosition() (but not in DecreasePosition() somehow), it is updated there as well. gmx3 However, globalShortAveragePrices is fetched and maintained by the newly introduced _shortsTracker. gmx6

image

As these occur at different levels of execution, the white-hat could use reentrancy to bypass the short avgp update at the PositionManager level and still trigger the short size update at the Vault level. The asynchronous updates were exploited to create discrepancies that manipulate the AUM calculation to the white-hat’s advantage.

Specifically, the attacker exploited the interaction between minting and staking GLP and opened a short position directly through the Vault contract. By bypassing the ShortsTracker, the attacker prevented the average short position price from being updated. This is done strategically when the market price is higher than the tracked average price, causing the protocol to overestimate unrealized losses. As a result, the Assets Under Management (AUM) calculation was inflated, increasing the apparent value of GLP. gmx7 The attacker could then redeem their GLP at an artificially elevated value, effectively withdrawing more funds than they initially deposited. gmx8

Key Transactions

https://arbiscan.io/tx/0x03182d3f0956a91c4e4c8f225bbc7975f9434fab042228c7acdc5ec9a32626ef

Attack Flow

Addresses

Exploiter wallets:

  • 0xDF3340A436c27655bA62F8281565C9925C3a5221
  • 0x414A734F7D9d204b3C30CBd66572685B8E675287
  • 0x6aCC60B11217A1fd0e68B0EcaEE7122d34A784c1
  • 0xa33Fcbe3b84Fb8393690D1E994B6A6aDC256D8A3
  • 0x639cd2fc24EC06bE64aaf94eB89392Bea98A6605
  • 0x99CdeB84064c2BC63de0CEa7C6978e272d0f2DAe
  • 0xe9Ad5a0F2697A3cF75FfA7328BdA93dBAeF7F7e7
  • 0x69c965e164fa60e37a851aA5CD82B13Ae39C1d95
  • 0x1DA7653D18B59bc19424d0017B21a045aD8DB038

Exploiter contract:

  • 0x7D3BD50336f64b7A473C51f54e7f0Bd6771cc355

GMX Vault:

  • 0x489ee077994B6658eAfA855C308275EAd8097C4A

GMX Order Book:

  • 0x09f77E8A13De9a35a7231028187e9fD5DB8a2ACB

GMX ShortsTracker:

  • 0xf58eEc83Ba28ddd79390B9e90C4d3EbfF1d434da

GMX GlpManager:

  • 0x3963FfC9dff443c2A94f21b129D429891E32ec18

Step by Step

Step 1: The attacker opened a new position using the attack contract as the account, then placed a small decreasing order in the GMX Order Book. gmx9

Step 2: The GMX off-chain keeper executed this order via PositionManager.executeDecreaseOrder(). gmx10 GMX Keeper → PositionManager.executeDecreaseOrder() → OrderBook.executeDecreaseOrder() → Router.pluginDecreasePosition() → Vault.decreasePosition()

Note that during the execution of this order, the PositionManager temporarily set the _isLeverageEnabled flag of the Vault contract to true, which enabled the OrderBook contract to execute a decreasing position operation via OrderBook.executeDecreaseOrder.

The decreasing position operation returned the released collateral (ETH) to the user, which was the attack contract. gmx11 The executeDecreaseOrder()->_transferOutETH()->_receiver.sendValue() function for ETH enabled the attacker to execute operation before the _isLeverageEnabled flag was reset to false. gmx12

Step 3: During reentrancy, the attack created a WBTC short position with 30 times leverage, 3,001 USDC * 30, via Vault.increasePosition() adding a substantial _sizeDelta of 90030000000000000000000000000000000 (90030e30), compared to the existing globalShortSize of 105403061114092959107000000000000000(105403e30) gmx13 without triggering the globalShortAveragePrices update. gmx14 The white-hat then placed a reverse normal (not through reentrancy) order to decrease the short position and retrieve most of the 3001 USDC.

The tactic was repeated five times. gmx15 As the WBTC global short average price updated after the decrease order was skipped by reentrancy, the white-hat was able to deflate the price, 108757787000274036210359376021024492 (~1.087e35), to 1913705482286167437447414747675542 (~1.913e33) ~57 times in just five iterations. gmx16 As a consequence of the last manipulation, a larger priceDelta contributed to a larger PnL at the denominator and resulted in a lower price and even larger priceDelta.

First iteration: priceDelta = ~109505e30-~108757e30 = ~747e30 size.mul(priceDelta).div(averagePrice) = 78840119444662794775583864191648649089204261998551356000000000000000 / 108757787000274036210359376021024492 GlobalShortAveragePrice = 104766755156748843189540879601516878 gmx17 Second iteration: priceDelta = ~109529e30 - ~104934e30 = ~4595e30 size.mul(priceDelta).div(averagePrice) = 1683806156985823019383613620000000000000000000000000000000000000000000

GlobalShortAveragePrice = 85421390228731999769933799789356123

Such a dynamic allows the exploiter to manipulate price in an accelerating pattern. gmx18

Step 4: In the final exploit, again, placing a decrease order on WETH and through executeDecreaseOrder()->_transferOutETH()->_receiver.sendValue() , the white-hat flashloaned 7.538M USD Coin, then minted 4,129,578 GLP tokens with 6M USD Coin via RewardRouter.mintAndStakeGlp. gmx19 According to GlpManager._addLiquidity(), mintedGLP = usdgAmount * glpSupply / aumInUSDG gmx29

image

gmx20 The first three terms in the AUM calculation by GlpManager are relatively stable, and volatility comes from the last term of shorts loss, of WBTC in this exploit.

usdgAmount = ~ 5,997,000 * 10^18 glpSupply = ~ 32324775445383446445240290 * 10^18 gmx21 poolAmounts = 11,439,302,230

globalShortSizes = 15373061114092959107000000000000000

globalShortAveragePrices = 1913705482286167437447414747675542

aum = 12160892925083681998303470188395218961

globalShortSizes = 15373061114092959107000000000000000

The total AUM Value to start 46942248263037264990037614165759809197 (~4.694e37).

Step 5: The white-hat opened a large short position for WBTC via Vault.increasePosition() with the remaining 1.538M USD Coin from flashloan. gmx22 Again, through reentrancy, the white-hat could directly call Vault.increasePosition() and increase the position without a globalShortAveragePrices update. gmx23 As the average price (for WBTC) was not updated in the shorts tracker, when getAUM() was called, it thinks that the increased short size is at the (NOT UPDATED) average price, which was less than the market price, so this inflated value was counted as a loss and added to the AUM value.

Initially, the global short size for WBTC was 15373061114092959107000000000000000 (~1.537e34), gmx24 Now the short size was set to 15373061114092959107000000000000000 + 15385676195700000000000000000000000000 = 15401049256814092959107000000000000000 (~1.54e37), 1000 times larger than previous.

The AUM was in turn inflated to 917911611253245890552483378294110666923(9.179e38), ~20 times larger than previous (~4.694e37).

Step 6: The white-hat performed multiple GLP burning operations (removing liquidity from GLP pools) via RewardRouter.unstakeAndRedeemGlp(). gmx25 The AUM was used to determine the amount of assets that the user's GLP can be redeemed for, effectively allowing the user to withdraw over 19x more value than what they initially deposited. gmx26 More than enough to drain the victim Vault and take ~$42M assets.

Step 7: The white-hat closed the large short position, retrieved collateral assets, and then repaid the flash loan.

Fund Flow

The ~$42M of assets were split into 5 wallets as follows:

  • 0xDF33 = $10,497,825.69
  • 0x639c = $7,586,724.5
  • 0xe9Ad = $8,429,850
  • 0xa33F = $8,429,850
  • 0x69c9 = $8,429,850

gmx27

The funds were then swapped for ETH before being returned to the GMX protocol two days later, with the white-hat keeping 1,700 ETH after returning 10k ETH.

gmx28

To keep up to date on the latest incident alerts and statistics follow @certikalert on X, or read our latest analysis on certik.com.

Related Blogs

SOF/LAXO Incident Analysis

SOF/LAXO Incident Analysis

In February 2026 two separate exploits occurred on the BNB Smart Chain (BSC), affecting SOF and LAXO tokens, leveraging the same class of vulnerability: a flawed token burn mechanism that allowed price manipulation within a single transaction.

Gyroscope Incident Analysis

Gyroscope Incident Analysis

On 30 January 2026, Gyroscope announced via their X account that they had paused liquidity pools due to an issue with their cross-chain contract. The issue led to losses of 6M Gyro Dollar (GYD) tokens with approximately $807k of liquidity extracted by the attacker.

Makina Incident Analysis

Makina Incident Analysis

On 20 January 2026, DeFi protocol MakinaFi suffered an exploit resulting in the theft of 1,299 ETH, valued at approximately $4.13 million.