Summary:
The PerpetualVault and GmxProxy contracts coordinate order creation and execution callbacks using global state variables—such as a single global OrderQueue in GmxProxy and the vault’s “flow” state in PerpetualVault—without binding each order to a unique vault state snapshot. As a result, if a new order is submitted before the callback for a previous order is processed, the global order data is overwritten. This misalignment causes the callback to operate on stale or mismatched state, potentially resulting in incorrect fee assessments, erroneous share minting, or collateral misallocations that harm depositor balances.
Issue Is in:
GmxProxy:
Uses a single global variable (an OrderQueue) to store the active order’s request key. Each call to createOrder or settle simply overwrites this value.
PerpetualVault:
Maintains its own “flow” state but does not bind order information (e.g. the request key) to a snapshot of the vault’s state. If two orders are submitted back‑to‑back, the vault’s expectation for a callback corresponding to the first order is lost.
Root Cause:
There is no on‑chain mechanism (such as unique order IDs linked with the vault’s state) to ensure that an order callback is processed against the exact state that existed when the order was created. As a result, if a new order is initiated before the callback for a previous order is processed—or if network delays cause callbacks to arrive out of order—the vault may update its state based on mismatched or stale order data.
Proof-of-Concept Scenario: (Foundry test below)
Scenario Setup:
The vault submits an order (Order1) with a unique key (orderKey1), and the proxy stores this key in its global queue.
Before the callback for Order1 is processed, the vault submits a second order (Order2) with a different key (orderKey2), which overwrites the proxy’s global queue.
Callback Mismatch:
When a callback for Order1 is later processed, the vault (or callback function) would expect the global queue to hold orderKey1.
However, the proxy’s queue now contains orderKey2. This mismatch demonstrates that the vault state is not correctly synchronized with the order data.
Outcome:
The callback processing uses the wrong order data, leading to incorrect fee accounting or collateral adjustments. This can be exploited or can result in inadvertent misprocessing, harming depositor balances.
Impact:
Invariant Violation: The core invariant of consistent share and fee accounting is broken.
Financial Risk: Incorrect processing of order callbacks can lead to misallocated funds or dilution of depositor positions.
Exploitation: An attacker or a misconfigured vault could trigger back‑to‑back orders to deliberately force a state mismatch.
Recommendation:
Unique Order Tracking:
Modify the design so that each order is recorded with a unique identifier and associated with a snapshot of the vault’s state.
State-Order Binding in Callbacks:
In the callback functions, verify that the order being processed matches the vault’s stored state (for example, by comparing the unique order ID stored in the vault with the one provided in the callback).
Sequential Order Enforcement:
Alternatively, enforce a strict sequential order submission policy such that a new order cannot be initiated until the callback for the previous order has been fully processed.
Severity:
High by likelyhood & impact
Below is a simplified simulation using Foundry that demonstrates the vulnerability. In this PoC, a simplified version of a proxy (simulating GmxProxy) and a vault (simulating PerpetualVault) are implemented. The vault submits an order and later submits a second order before processing the callback for the first order. A callback simulated for Order1 then detects a mismatch in the stored order key.
src/FakeGmxProxy.solsrc/FakeVault.soltest/FakeVaultTest.t.solRun the Test:
From the project root, execute:
confirming that when two orders are submitted consecutively, the global order key is overwritten. Consequently, a callback expecting the first order's key fails the check—demonstrating the vulnerability.
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.
Order is proceed one by one and requestKey is only used to cancelOrder. I didn’t see any real scenario where it will cause a problem. Flow and gmxLock will prevent that to happen.
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.