This analysis investigates a 42m attack on the GMX protocol. We provide detailed technical analysis of vulnerability and include work reproduction of attack scenarios for educational purposes in a forked environment.
Use the attack Mutual contract re -vulnerability Increases the detoured access control while the position increases. As a result, GLP token prices were operated at a higher price, allowing attackers to repay the tokens and extract profits from protocols.
Reproduction with Wake
- Replicate the repository
- GMX project dependency import:
$ npm i
- Initialization Wake:
$ wake up
- Receive and set ARBITRUM for URL from alchemy or other providers.
.env
Similar.env.example
. - Execution:
$ wake test tests/test_attack_simple.py
- compromise
print(tx.call_trace)
To see the call tracking.
Root cause
The vulnerability comes from re -entry. Re -entry itself is simple, but its impact is important.
Core problem: GLP token price calculation globalShortAveragePrices
Variable ShortsTracker
. This dependence creates an exploited attack vector.
The vulnerability is a re -creation of mutual contracts. Many contracts have been related during the transaction. Each contract has a re -creation guard. However, the re -creation has already occurred after the termination of a specific contract.
Entry
The attack begins when the user increases the position.
- User call
createIncreaseOrder
To register an order - Order Keeper Bot calls
PositionManager.executeIncreaseOrder
Run it - within
executeIncreaseOrder
,,,ShortsTracker.updateGlobalShortData
Called
ShortsTracker.updateGlobalShortData
save globalShortAveragePrice
In the case of tokens -average input price of all short positions. This value directly affects GLP token price calculations.
contract PositionManager
function executeIncreaseOrder(
address _account,
uint256 _orderIndex,
address payable _feeReceiver
) external onlyOrderKeeper
//...
IShortsTracker(shortsTracker).updateGlobalShortData(_account, collateralToken, indexToken, isLong, sizeDelta, markPrice, true);
ITimelock(timelock).enableLeverage(_vault); // isLeverageEnabled <- True
IOrderBook(orderBook).executeIncreaseOrder(_account, _orderIndex, _feeReceiver);
ITimelock(timelock).disableLeverage(_vault); // isLeverageEnabled <- False
_emitDecreasePositionReferral(_account, sizeDelta);
External currencies achieve this path Vault
:
OrderBook.executeIncreaseOrder
Router.pluginIncreasePosition
that decreasePosition
The flow follows a similar pattern.
that Vault.increasePosition
The function checks it isLeverageEnabled
Equivalent True
Make sure the call occurs Timelock.enableLeverage
and Timelock.disableLeverage
. This inspection turned out to be insufficient.
contract Vault {
// function has no msg.sender check.
// Assumes caller transfers tokens or at least the caller is trusted.
function increasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _sizeDelta,
bool _isLong
) external override nonReentrant
_validate(isLeverageEnabled, 28); // this will be bypassed
_validateGasPrice();
_validateRouter(_account);
...
...
during Vault.decreasePosition
The contract transmits a collateral token for the closed location. If the mortgage token is Weth, the system withdrew the ETH and sent it to the user’s account. In particular, these WETH work occurs outside Vault
contract.
The call flow proceeds as follows:
OrderBook.executeDecreaseOrder
Router.pluginDecreasePosition
Vault.decreasePosition
- REENTRANTRANCYGUARD set
ENTERED
Vault
Close the location- Send Weth to Orderbook
- REENTRANTRANCYGUARD set
NOT_ENTERED
- REENTRANTRANCYGUARD set
OrderBook
Withdraw the ETH- ETH is sent to the user
User.receive
TriggerVault.increasePosition
(Abuse)- Reentrancyguard checks
NOT_ENTERED
- REENTRANTRANCYGUARD has been set
ENTERED
- The attack continues…
- Reentrancyguard checks
Re -creation guard Vault
Start NOT_ENTERED
However, after this status is reset, a re -entry call occurs and bypassed protection.
Attack escalation
directly Vault.increasePosition
Bypass call ShortsTracker.updateGlobalShortData
cause GlpManager.getAum
Returns the expansion value and artificially increases the price of GLP tokens.
Attack order:
- It goes back through an open entry point
- To get GLP tokens, add fluidity
- call
increasePosition
GLP token price is manipulated up - Remove liquidity at the expansion GLP token price
Operation details
Used by an attacker RewardRouterV2.mintAndStakeGlp
because GLPManager.inPrivateMode
It is activated by preventing direct calls GLPManager.addLiquidity
.
The attacker uses a flash loan with a USDC to create a large WBTC short position.
summation
The attack was successful due to the fragmentary data responsibility for the contract. Important status information is divided ShortsTracker
and Vault
REENTRANTRANTRANCY Guard is inefficiently rendered. This vulnerability has made the attacker manipulates the price of GLP tokens through a carefully adjusted re -entry phone to enable millions of exploits.