GmxProxy.sol contains critical functions that perform external calls (e.g. order creation and callbacks) without explicit reentrancy protection. Although access is restricted to trusted callers (e.g. the perpetual vault and designated GMX handlers), the absence of reentrancy guards may allow an attacker to exploit unexpected reentrancy paths if trust assumptions are broken.
Issue:
Critical functions such as createOrder, settle, afterOrderExecution, and afterOrderCancellation do not use a reentrancy guard (e.g. OpenZeppelin’s nonReentrant modifier) despite performing external calls.
Context:
Although these functions are callable only by trusted addresses (e.g. perpVault), an attacker that compromises one of these trusted contracts or manipulates the control flow during an external call could reenter the function and corrupt internal state.
Inter‑Contract Considerations:
The design assumes that only a trusted perpetual vault calls these functions; however, a failure in these assumptions could allow reentrancy attacks.
State Corruption:
Reentrant calls could lead to unexpected state changes, such as duplicative order creation or cancellation.
Fund Loss:
An attacker could potentially manipulate fund transfers, causing unauthorized ETH or token transfers.
Order Manipulation:
Incorrect order parameter handling could lead to economic losses due to misconfigured orders.
Proof of concept (POC):
Overview
This PoC demonstrates how the lack of a reentrancy guard in critical functions of the GmxProxy contract (e.g. the cancelOrder function) could allow an attacker if the trusted caller (perpVault) is compromised to reenter and invoke the function multiple times. In this scenario, a malicious vault simulates the trusted caller and leverages the fallback mechanism to reenter the vulnerable function.
Attacker: The malicious vault contract that simulates a compromised trusted caller.
Victim: The vulnerable GmxProxy contract.
Protocol: The overall system expecting only controlled calls from the trusted perpVault.
Setup:
Deploy the VulnerableGmxProxy contract. The deployer becomes the trusted perpVault.
Deploy the MaliciousVault contract, providing it the address of the vulnerable proxy.
Attack Execution:
The attacker (via the MaliciousVault) calls initiateAttack().
The proxy’s cancelOrder() is called by the trusted address (the malicious vault).
During the execution of cancelOrder(), the external call triggers the trigger() function in the malicious vault.
In trigger(), the malicious vault reenters cancelOrder() before the first execution completes, allowing duplicate state updates.
Result:
The vulnerable function is executed twice, which could corrupt internal state or lead to unintended fund transfers if similar patterns occur in a real scenario.
Manual Code Review
Implement ReentrancyGuard:
Inherit from OpenZeppelin’s ReentrancyGuard and mark vulnerable functions with the nonReentrant modifier.
Internal State Checks:
Update critical state variables before making any external calls to prevent reentrant interference.
Defense in Depth:
Even if access is restricted, adding reentrancy protection is a best practice to safeguard against future changes in trust assumptions.
Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.
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.
Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.