DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Transaction Gas Price Manipulation in GmxProxy via PerpetualVault.withdraw()

Summary

A vulnerability exists in the GmxProxy contract where tx.gasprice is used to calculate execution fees. While most functions have appropriate access controls, this vulnerability can be exploited by users through the public withdraw()function in PerpetualVault, potentially draining ETH from the contract.

Vulnerability Details

The attack path works as follows:

Users can call the public withdraw() function in PerpetualVault:

// In PerpetualVault.sol
function withdraw(address recipient, uint256 depositId) public payable nonReentrant {
_noneFlow();
flow = FLOW.WITHDRAW;
flowData = depositId;
// [validations...]
depositInfo[depositId].recipient = recipient;
_payExecutionFee(depositId, false);
if (curPositionKey != bytes32(0)) {
nextAction.selector = NextActionSelector.WITHDRAW_ACTION;
_settle(); // This is the vulnerable call
} else {
// [...]
}
}

The _settle() function in PerpetualVault calls gmxProxy.settle():

// In PerpetualVault.sol
function _settle() internal {
IGmxProxy.OrderData memory orderData = IGmxProxy.OrderData({
// [order data setup...]
});
_gmxLock = true;
gmxProxy.settle(orderData);
}

The settle() function in GmxProxy uses tx.gasprice for fee calculation:

// In GmxProxy.sol
function settle(IGmxProxy.OrderData memory orderData) external returns (bytes32) {
require(msg.sender == perpVault, "invalid caller");
uint256 positionExecutionFee = getExecutionGasLimit(Order.OrderType.MarketDecrease, orderData.callbackGasLimit) * tx.gasprice;
require(address(this).balance >= positionExecutionFee, "insufficient eth balance");
gExchangeRouter.sendWnt{value: positionExecutionFee}(orderVault, positionExecutionFee);
// [...]
}

This chain of calls allows an ordinary user to indirectly trigger a function that uses tx.gasprice for calculating fees, which could be manipulated to drain ETH from the contract and send it to GMX.

Impact

A malicious user can exploit this vulnerability to:

  1. Drain ETH from GmxProxy: By setting an extremely high tx.gasprice when calling withdraw(), the user can cause GmxProxy to send excessive amounts of ETH to the orderVault. This is particularly severe because there's no upper bound on the execution fee.

Tools Used

Manual code review

Recommendations

The most robust mitigation would be to implement a gas price oracle system that provides reliable gas price data for both Arbitrum and Avalanche networks, as the protocol will be deployed on both platforms.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_tx-gasprice_user_manipulation

If the sender does not provide enough, the transaction to create the order won't be included in the current block: no problem. If the user provides more, they will pay more: user mistake. Moreover, the `refundFee` is set to `true` only when the keeper is the caller, preventing manipulation.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!