Assessment reports>Aori 0.3.1 Upgrade>Medium findings>Missing reentrancy guard in the ,cancel, function
Category: Coding Mistakes

Missing reentrancy guard in the cancel function

Medium Impact
High Severity
Low Likelihood

Description

The source-chain cancel function allows a solver to cancel an active single-chain order or allows the offerer to cancel the single-chain order when it expires.

However, the cancel function lacks a nonReentrant modifier, exposing it to potential reentrancy attacks.

function cancel(bytes32 orderId) external whenNotPaused {

Impact

If a solver's account were compromised, an attacker could exploit this vulnerability for profit. By converting the solver's address into a malicious contract via EIP-7702, the attacker can execute a reentrancy attack during a native token transfer.

An attacker could perform the following steps:

  1. Create orders. The attacker, in control of a solver on Arbitrum, creates two orders.

    • Order 1: Deposit 2,500 USDT on Arbitrum → receive 1 ETH on Arbitrum (recipient: solver address)

    • Order 2: Deposit 2,500 USDT on Arbitrum → receive 2,500 USDC on Optimism

  2. Fill order 1. The attacker uses the compromised solver to fill order 1. The native ETH transfer to the solver's address triggers the malicious contract's fallback function.

  3. Reenter cancel. Inside the fallback function, the malicious contract calls the cancel function for order 1. Because there is no reentrancy guard, the call succeeds. The attacker's locked USDT balance decreases due to both cancel and fill actions, resulting in a zero locked balance.

  4. Exploit order 2. Since the attacker's locked USDT balance on the source chain (Arbitrum) is zero, any attempt to settle order 2 will fail on Arbitrum. However, solvers on the destination chain (Optimism) may still attempt to fill order 2. Each time an Optimism solver fills the order, the attacker receives 2,500 USDC on Optimism, while the order status remains active because the source-chain settlement fails repeatedly.

Recommendations

Add a reentrancy guard to the cancel function.

-function cancel(bytes32 orderId) external whenNotPaused {
+function cancel(bytes32 orderId) external nonReentrant whenNotPaused {

Remediation

This issue has been acknowledged by Aori, and a fix was implemented in commit 0b18c84f.

Zellic © 2025Back to top ↑