Skip to content

Latest commit

 

History

History
48 lines (31 loc) · 2.03 KB

001.md

File metadata and controls

48 lines (31 loc) · 2.03 KB

Urban Fiery Guppy

High

createOrder will be abused to drain all approvals

Summary

createOrder uses generateOrderId, which returns the same value within one block for the same recipient:

    ///@notice generate a random and unique order id
    function generateOrderId(address sender) external view override returns (uint96) {
        uint256 hashedValue = uint256(
            keccak256(abi.encodePacked(sender, block.timestamp))
        );
        return uint96(hashedValue);
    }

As there is no access control for order creation, and funds are transferred from the recipient (not msg.sender), it is possible to drain all approvals by creating orders with minAmountOut = 0.

Root Cause

Missing msg.sender == order.recipient check in createOrder; usage of only recipient and block.timestamp for orderId derivation.

Internal pre-conditions

No response

External pre-conditions

Any user who approves any whitelisted token to the OracleLess/Bracket/StopLimit contract.

Attack Path

  1. User approves 10_000 USDC to OracleLess contract, creates an order for 10_000 USDC

  2. Attacker's contract iterates through pendingOrderIds, starting from the last element, records all orders that were created during the current block.

  3. In the same transaction, for each such order, Attacker's contract calls createOrder, with the same data but minAmountOut = 0. generateOrderId generates the same id, because it depends only on the block.timestamp and recipient, so the attacker's createOrder overwrites the order created by the victim.

  4. In the same transaction, attacker's contract calls fillOrder, and swaps all victim's funds for 0.

Alternatively, attacker can monitor approvals of whitelisted tokens to the contract, and createOrder with minAmountOut = 0, and amount = approvedAmount.

Impact

All users who approved a whitelisted token to contracts OracleLess/Bracket/StopLimit, will lose the whole approved amount.

Mitigation

Use nonce for deriving orderId, and validate msg.sender == recipient.