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

Lack of gPath Validation Compromises Secure Swap Operations

Data Validation, Logic Issue

Summary

The _doGmxSwap function in the GmxProxy contract executes swaps using a gPath array without enforcing strict on-chain validation. While keeper authorization and GMX checks reduce direct exposure, a compromised or malicious keeper could provide harmful swap routes leading to suboptimal trades or fund losses.

Vulnerability Details

The _doGmxSwap function takes a gPath parameter that defines the swap path for tokens but does not verify whether each token in the path is safe or approved by the protocol. Although only an authorized keeper can call this function (via _onlyKeeper()), relying primarily on the keeper’s integrity and GMX’s partial checks creates a single point of failure:

  • Security Guarantee Broken: Defense-in-depth is undermined because there is no fallback if the keeper is compromised or if a malicious token is integrated.

  • Propagation of Malicious Input: A malicious keeper can pass a gPath containing attacker-controlled tokens or illiquid assets, causing detrimental trades and value extraction at the vault’s expense.

Impact

Impact: Medium

  • Potential Financial Damage: Swaps could result in unexpectedly large price slippage, low-value tokens, or direct exploitation of collateral.

  • Mitigating Factor: Only the keeper role can invoke _doGmxSwap, reducing the number of possible attackers and limiting large-scale, immediate exploitation.

  • Likelihood: Low

    • Keeper Compromise Required: Exploitability hinges on compromising the keeper or misconfiguring which tokens are considered legitimate.

    • Partial GMX Protections: GMX rejects some invalid routes, imposing an additional barrier, though it does not fully validate intermediate tokens.

Tools Used

Keeper Compromise

  • An attacker gains control of the keeper’s private key or convinces governance to replace the keeper with a malicious address.

  • Malicious Swap Path

    • The attacker calls runNextAction (or run) with a crafted gPath.

    • Example:

      // Instead of a straightforward swap like [collateralToken, indexToken],
      // the attacker includes a token M they fully control:
      gPath = [collateralToken, TokenM, indexToken];
  • Execution and Value Extraction

    1. The vault swaps collateralToken -> TokenM.

    2. The attacker manipulates TokenM’s price, either inflating it to capture more collateral or dumping it to yield fewer index tokens in the final trade.

    3. The vault then attempts TokenM -> indexToken, ultimately receiving significantly less index tokens than anticipated.

  • Outcome

    • Vault Loss: The vault or its users bear the brunt of the unfavorable swap, losing collateral value.

    • Attacker Profit: The attacker pockets arbitrage gains or extracts direct value from the manipulated token.

Recommendations

Implement strict on‑chain validation of the decoded swap path.

1. Declare a Maximum Path Length and an Allowlist Mapping

// Maximum allowed length for a swap path.
uint256 constant MAX_PATH_LENGTH = 5; // adjust as needed
// Allowlist mapping for approved tokens in swap routes.
mapping(address => bool) public approvedTokens;

2. Helper Function for Swap Path Validation

function _validateGmxSwapPath(
address[] memory gPath,
address expectedInput,
address expectedOutput
) internal view {
require(gPath.length >= 2, "Invalid path length");
require(gPath.length <= MAX_PATH_LENGTH, "Path too long");
require(gPath[0] == expectedInput, "Invalid input token in path");
require(gPath[gPath.length - 1] == expectedOutput, "Invalid output token in path");
for (uint i = 1; i < gPath.length - 1; i++) {
require(approvedTokens[gPath[i]], "Intermediate token not approved");
}
}

3. Optional Function for Managing the Allowlist

function setApprovedToken(address token, bool approved) external onlyOwner {
approvedTokens[token] = approved;
}

4. Modify the doGmxSwap Function

function _doGmxSwap(bytes memory data, bool isCollateralToIndex) internal {
Order.OrderType orderType = Order.OrderType.MarketSwap;
(address[] memory gPath, uint256 amountIn, uint256 minOutputAmount) =
abi.decode(data, (address[], uint256, uint256)); // decode swap data
// Determine expected input and output tokens based on the swap direction.
address expectedInput;
address expectedOutput;
if (isCollateralToIndex) {
expectedInput = address(collateralToken);
expectedOutput = address(indexToken);
} else {
expectedInput = address(indexToken);
expectedOutput = address(collateralToken);
}
// Validate the swap path before proceeding.
_validateGmxSwapPath(gPath, expectedInput, expectedOutput);
swapProgressData.remaining = amountIn;
swapProgressData.isCollateralToIndex = isCollateralToIndex;
// The token being swapped is the expected input.
address tokenIn = expectedInput;
IERC20(tokenIn).safeTransfer(address(gmxProxy), amountIn);
IGmxProxy.OrderData memory orderData = IGmxProxy.OrderData({
market: address(0),
indexToken: address(0),
initialCollateralToken: tokenIn,
swapPath: gPath,
isLong: isCollateralToIndex, // Use to indicate swap direction.
sizeDeltaUsd: 0,
initialCollateralDeltaAmount: 0,
amountIn: amountIn,
callbackGasLimit: callbackGasLimit,
acceptablePrice: 0,
minOutputAmount: minOutputAmount
});
_gmxLock = true;
gmxProxy.createOrder(orderType, orderData);
}

This enforces a strict on‑chain validation of the swap path by:

  • Ensuring the path is neither too short nor too long,

  • Confirming the first element equals the collateral (or index) token and the last element matches the expected output

  • Verifying every intermediate token is approved via the approvedTokens allowlist.

Updates

Lead Judging Commences

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

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

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

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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