GMX engaged Guardian to review the security of their Gasless transactions support. From the 27th of January to the 3rd of February, a team of 4 auditors reviewed the source code in scope.
- Published
- Review window
- January 27 to February 3, 2025
- Language
- Solidity
- Chains
- Arbitrum
- Sector
- Perpetuals
- 0 Critical
- 5 High
- 4 Medium
- 18 Low
- 0 Informational
Scope
Overview
GMX engaged Guardian to review the security of their Gasless transactions support. From the 27th of January to the 3rd of February, a team of 4 auditors reviewed the source code in scope.
Issues Detected Throughout the engagement 5 High/Critical issues were uncovered and promptly remediated by the GMX team.
Findings 27
-
H-01 High Atomic Swaps With Normal Fees Gaming Resolved
Description
The introduction of fee swaps to pay the executor allows for users to do arbitrarily large swaps in a single transaction without first initiating this action on chain.
Before the introduction of gasless transactions this ability was not allowed on the GMX Exchange and it was explicitly disallowed for atomic withdrawals to include swaps.
Gasless transactions unintentionally introduces a way for users to achieve single transaction swaps by using a higher than needed fee swap input amount and receiving the excess amount back.
Furthermore, the swap made in this instance uses the normal swap fees as computed by the
SwapUtils.swapfunction. There is no application of theAtomicSwapfee pricing.Recommendation
Consider removing the fee swap feature so that the ability for users to perform swaps in a single transaction is not unintentionally introduced with this update.
Otherwise, keep the feature and limit the size of swap that is allowed to be carried out from this, and furthermore charge the higher
AtomicSwapfee rate for these swaps.Resolution
GMX Team: Resolved.
-
H-02 High Missing Update Order Fee Logic Logical Error Resolved
Description
In the
_updateOrderfunction there is no logic to support sending wnt tokens to the order vault to cover any fee increase related to the update of an order.This means that any order updates which result in a higher
executionFeebeing required will not be possible through gasless transactions.Recommendation
Include logic to transfer additional
executionFeewnt value to theOrderVaultto be able to successfully update orders which would have an increasedexecutionFee.Resolution
GMX Team: Resolved.
-
H-03 High Missing decreasePositionSwapType Validation Logical Error Resolved
Description
In the
_getCreateOrderStructHashthedecreasePositionSwapTypevalue is not included in the resulting hash and therefore cannot be validated.The caller of the
createOrderfunction can then decide the value of the_getCreateOrderStructHashon the params.This can be used to cause loss or unexpected outcomes for the user as their position and integrating addresses may not have support for a particular receiving token.
Recommendation
Include the
params.decreasePositionSwapTypein the_getCreateOrderStructHashfunction.Resolution
GMX Team: Resolved.
-
H-04 High Lacking Cancellation Receiver Validation Validation Resolved
Description
The
SubaccountRoutercontract lacks validation for the cancellation receiver in thecreateOrderfunction.This way sub accounts can potentially create orders with a large
initialCollateralDeltaAmounton them and cancel them with thecancellationReceiveras their own address to drain the main account's assets.Recommendation
Consider adding the
cancellationReceivervalidation to thecreateOrderfunction in theSubaccountRoutercontract.Resolution
GMX Team: Resolved.
-
H-05 High callbackContract Siphons Refunds Validation Resolved
Description
In the
createOrderfunction thereceiverandcancellationReceiveraddresses are validated against the account to ensure that funds are not sent to an address that is not controlled by the position owner.However there is no validation on the callback contract which will take a higher priority than the
cancellationReceiverorreceiverwhen theexecutionFeeis refunded.Recommendation
If it is important for the protocol to ensure that sub accounts cannot siphon the refund fee this way, consider validating that the provided callback contract is the saved callback contract for the account and market.
Otherwise be aware of this issue and clearly document it for users and integrators of the sub account feature.
Resolution
GMX Team: Resolved.
-
M-01 Medium removeSubaccount Cannot Be Gasless Logical Error Resolved
Description
The
removeSubaccountfunction is not outfitted to be a gasless transaction function. The function is missing the_handleRelaylogic and does not have aonlyGelatoRelaymodifier.Recommendation
Outfit the
removeSubaccountfunction so that it can be used by the Gelato relayer in a gasless manner.Resolution
GMX Team: Resolved.
-
M-02 Medium Unused Permit DoS DoS Resolved
Description
In the
_handleTokenPermitsfunction if the existing allowance for the spender is greater than the required amount then the permit signature is not used.However this allows for a malicious DoS in the future because the permit signature is now public and the corresponding nonce has not been used.
The next time the same signer wishes to use the corresponding nonce for a permit to the same token a malicious actor can submit the permit they signed in the past to use the corresponding nonce before the user's newly signed permit is executed.
This can be carried out for future interactions with the GMX system or any other permit application for the token.
Recommendation
Consider always using the permit signature no matter if it is unnecessary and instead determine if the permit is necessary at the UI level.
Resolution
GMX Team: Resolved.
-
M-03 Medium subAccount Is Not Fully Refunded In Top Up Logical Error Acknowledged
Description
When determining how much to top up it the contract calculates the amount of gas used as follows:
uint256 nativeTokensUsed = (startingGas - gasleft()) * tx.gasprice + executionFeeThe issue with this is that there is ample logic and gas consumed after this calculation. None of which will be considered for refund. Meaning that a sub account will always get an insufficient refund in terms of the additional top up logic.
Recommendation
Add a
topUpgasvariable to the calculation which contains the amount of gas that will be consumed after the calculation.Resolution
GMX Team: Acknowledged.
-
M-04 Medium Swap Occurs Without Market Update Logical Error Acknowledged
Description
Before any action is executed that a user can take GMX will call
updateFundingAndBorrowingStateto update the borrowing rate of traders in the underlying pool.However currently a swap through the gelato routers will occur without making any update which means that subsequent borrowing fee rate calculations are incorrect between the period of the swap and the next position update. Causing an incorrect amount of borrowing fees to be charged.
Recommendation
Consider updating the borrowing and funding state with
updateFundingAndBorrowingStatebefore a swap occurs in a market.Resolution
GMX Team: Acknowledged.
-
L-01 Low Subaccounts Access To Funds Are Not Partitioned Unexpected Behavior Acknowledged
Description
An account can have many sub accounts all of which will have access to the same funds. Because of this users may end up having more funds traded then expected.
Recommendation
Consider giving the user control over how much a sub account can spend, or document to users that all sub accounts share the same total allowance
Resolution
GMX Team: Acknowledged.
-
L-02 Low Comingling Of Gelato And GMX Fee Logical Error Acknowledged
Description
The execution fee and gelato fee come from the same source,
fee.feeAmount. That means if a user wants to use USDC to pay gelato when creating an order they will have to pay a (swap) fee to pay a (gelato) fee.It also means that
executionFeefor GMX will not be sufficient at times since forcreateOrderit is just sending over the residual amount, so even in cases where there is no swap there is still the case where Gelato fee increases and reduces the residual amount that can be used for GMXexecutionFee.Recommendation
Consider separating the execution fee and the gelato fee so that users can provide
wntfor the execution fee without paying a fee on it.Resolution
GMX Team: Acknowledged.
-
L-03 Low Unused Enum Superfluous Code Resolved
Description
In the
Errors.solfile theSignatureTypeenum is not used throughout the codebase.Recommendation
Remove the unused
SignatureTypeor implement it's intended use-case.Resolution
GMX Team: Resolved.
-
L-04 Low Lacking Feature Validation Validation Resolved
Description
There is currently no feature to deactivate gasless transactions in the event that they need to be.
Recommendation
Consider adding a gasless transactions wide feature that can be disabled, and when disabled no gasless transactions can be executed.
Resolution
GMX Team: Resolved.
-
L-05 Low Permit Frontrunning Frontrunning Resolved
Description
In the
_handleTokenPermitsfunction a permit is made to an arbitrary token. However since the permit signature must exist in the transaction calldata it is visible in the mempool for chains like Avalanche which have a public mempool.This allows malicious actors to frontrun the relayer and submit this permit in a separate transaction, causing the relayer's execution of the action to fail.
Recommendation
Either ensure that the relayer is using a private RPC or consider adding logic to continue if the permit action fails, since in the case where a malicious actor has frontrun the permit the approved value has already been given.
Resolution
GMX Team: Resolved.
-
L-06 Low Bypassing Subaccount Disabled Feature Logical Error Acknowledged
Description
The
SubaccountGelatoRelayRouterallows users to create, update and cancel orders using asubaccountand relaying transaction with Gelato. All subaccount GMX interactions are done directly using theSubaccountUtils, skipping theSubaccountRouter.During
_handleSubaccountAction, it will validate if the subaccount feature is enabled for theSubaccountGelatoRelayRouter.Therefore, if the sub account feature is disabled for
SubaccountRouter, it will still be available using.SubaccountGelatoRelayRouter. This can create unexpected scenarios, if both features are not disabled at the same time.Recommendation
Document this scenario and make sure that both subaccount features are disabled at the same time.
Resolution
GMX Team: Acknowledged.
-
L-07 Low Missing Swap Path Validation Validation Resolved
Description
The
_swapFeeTokensfunction does not perform any validation on the length of the swap path provided. This does not adhere to the maximum swap length allowed on the GMX exchange for canonical orders.Recommendation
Consider validating the swap path in the
_swapFeeTokensfunction to avoid any unexpected behaviors.Resolution
GMX Team: Resolved.
-
L-08 Low Missing MaxFee Validation For Relayer Validation Resolved
Description
The router contracts will pay the Gelato relayer a fee during
_transferRelayFee. To ensure there is a heightened control over the fees, Gelato suggests to use_transferRelayFeeCappedwith amaxFeethat will prevent transactions to be executed if the relayer fee is above a certain limit.Recommendation
Introduce a
maxFeeparameter, either in the function call, or as a state variable, and use_transferRelayFeeCappedinstead.Resolution
GMX Team: Resolved.
-
L-09 Low removeSubaccount Marked As Payable Modifiers Resolved
Description
The
payablemodifier is added to theremoveSubaccountfunction, however this function does not do anything with the accepted Ether value.Recommendation
Remove the
payablemodifier from theremoveSubaccountfunction.Resolution
GMX Team: Resolved.
-
L-10 Low Duplicated orderKey Events Unexpected Behavior Resolved
Description
In the swap for the fees for
_swapFeeTokenstheorderKeyprovided is the same as the order key that will be created.The order that is created could also be a swap order and thus there may be confusion about which events correspond to the order execution and which correspond to the fee swap for the order.
Recommendation
Confirm whether or not this is expected behavior. If it is not or the behavior should be made more clear, consider assigning a different order key which is unique to, but different from, the order being swapped for in the fee swapped.
Resolution
GMX Team: Resolved.
-
L-11 Low Nonce Dependence Prevents Subsequent Actions DoS Acknowledged
Description
In the Relay Signature verification logic for
_validateCalland_handleSubaccountApprovala monotonically increasing nonce is used to validate actions by a signer.However since the message nonce execution must be in order if multiple messages were to be signed and one message were to fail execution then it would prevent all subsequent messages from being executed.
The message could fail execution for a number of reasons including but not limited to a deadline invalidation, a swap failure, or an errantly missing approval.
Recommendation
Consider using unique nonces which are not required to be monotonically increasing so that if one message fails it does not prevent messages signed with a higher nonce from being executed.
Resolution
GMX Team: Acknowledged.
-
L-12 Low Redundant Required Fee Check Superfluous Code Acknowledged
Description
The contract validates if the
requiredRelayFeesent by Gelato Router is greater than the output amount returned fromswapFeeTokens.However, the function will still revert without that validation, during
_transferRelayFeeduring the token transfer if the relay params did not specify the correct amount.Similarly, if the remaining fee tokens (residual) are not enough to cover the
executionFee, the transaction will revert in theorderHandlercall.Recommendation
Avoid redundant token balance checks as they are already handled during transfer functions.
Resolution
GMX Team: Acknowledged.
-
L-13 Low Missing validateMarketTokenBalance Validation Validation Acknowledged
Description
In the
_swapFeeTokensfunction there is novalidateMarketTokenBalancevalidation after the swap. However this validation is performed throughout the codebase whenever a swap occurs to validate that no market balances were perturbed by a swap.Recommendation
Add
validateMarketTokenBalancevalidation after the swap is invoked in the_swapFeeTokensfunction.Resolution
GMX Team: Acknowledged.
-
L-14 Low Tokens Which Do Not Support Permit Validation Acknowledged
Description
The
_handleTokenPermitsfunction does not validate that each target token supports the permit functionality.This lack of validation can lead to unexpected behaviors if the permit function is routed to a token contract's fallback function instead of the expected permit function, which does not exist on that token. No particularly malicious behaviors on popular tokens has been identified at this time.
However with many tokens being supported on the GMX system and more to be added in the future, out of an abundance of caution it may be appropriate to validate that the tokens used with the
_handleTokenPermitsfunction are a whitelisted for permit use within GMX.Recommendation
Consider adding validation to ensure that tokens used in the
_handleTokenPermitsfunction do indeed support permit functionality and are allowed by a whitelisted list.Resolution
GMX Team: Acknowledged.
-
L-15 Low Unnecessary Wnt Transfers To/From OrderVault Superfluous Code Resolved
Description
The
_handleRelayFeewill handle Gelato relay fee payment, as well as GMXexecutionFee. However, when the fee token iswnt, it will perform unnecessary transfers from/to theorderVault:- transfer tokens from user to
OrderVault(_handleRelayFee) - transfer out
feeAmountfromOrderVault(_swapFeeTokens) - transfer relay fee to collector (
_transferRelayFee)
Recommendation
Do not transfer fee tokens from user to
orderVaultif thefee.feeToken = wntand instead send them to the router contract. Then, avoid the call to_swapFeeTokensand only call_transferRelayFeeas the tokens are already in the router.Resolution
GMX Team: Resolved.
- transfer tokens from user to
-
L-16 Low Account Can Steal executionFee From subAccount Warning Acknowledged
Description
An account can steal funds from the subaccount by manipulating the top up amount. The way this would be done is an account would signal to the sub account to create an order.
Then the account will frontrun the sub account and decrease the top up amount, this will truncate the amount the sub account should be refunded to only a dust amount.
Next the account will cancel the order where the execution fee will be sent to the cancelation receiver (account). If the subaccount is a bot or has any automation this attack would be easy to repeat stealing funds each time.
Recommendation
Consider putting a small time lock on
setSubaccountAutoTopUpAmountandsetMaxAllowedSubaccountActionCountResolution
GMX Team: Acknowledged.
-
L-17 Low Account Can Avoid Refunding Subaccount Logical Error Acknowledged
Description
When an account does not have enough funds or allowance to repay the subaccount in the
_autoTopUpSubaccountfunction it will return early. An account can leverage this by frontrunning a sub account and revoking allowance or transferring funds.Leading to the sub account not being compensated for paying the execution fee. An account can do this repeatedly to avoid all execution fee costs.
Recommendation
Instead of returning early either revert, or include an additional parameter where the sub account can choose if they want to waive the refund.
Resolution
GMX Team: Acknowledged.
-
L-18 Low SubAccount Can Make Account Lose Funds Warning Acknowledged
Description
The user can generate a sub account, the sub account action is managed by sub account router. However, in the newly added code, the sub account, if compromised, can directly make the main account lose money by executing a swap.
The swap logic let the main account transfer the
fee.feeTokenand swap the fee token to output WETH token to pay for the relayer fee. The swap has minimum slippage control (minOutputAmountis _getFee()), so the main account can suffer from slippage loss when executing the swap.The sub account can also compose a long swap path market pass to force the main account pay high gelato relayer fee.
Recommendation
Document such attack vector if the sub account is compromised. Validate the
fee.feeSwapPathand the amount of fee token (input token) the sub account can be used to swap for the WETH relayer fee.Resolution
GMX Team: Acknowledged.
No findings match.
More from GMX
All 44 reportsPut your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
