Lone Midnight Stallion
High
Currently, we do not use a nonce when generating the orderId
. As a result, orders can be replaced by manipulating the orderId
.
No response
No response
No response
- An attacker monitors the network.
- A user calls the
createOrder
function on theOracleLess
contract withamountIn = 10 ether
. - The attacker calls the
createOrder
function withamountIn = 9 ether
. - The attacker calls the
createOrder
function withamountIn = 1 ether
. - The attacker front-runs the user's transaction, executing all transactions in the same block.
Since we only use the owner's address and
block.timestamp
to generate theorderId
, all transactions execute with the sameorderId
.
The owner loses their tokens without an additional order being created. Even if the owner cancels the order, 9 ether will be lost.
No response
- Use
msg.sender
to ensure that the order is tied to the specific user. https://github.com/sherlock-audit/2024-11-oku/blob/main/oku-custom-order-types/contracts/automatedTrigger/OracleLess.sol#L38
function createOrder(
IERC20 tokenIn,
IERC20 tokenOut,
uint256 amountIn,
uint256 minAmountOut,
- address recipient,
uint16 feeBips,
bool permit,
bytes calldata permitPayload
) external override returns (uint96 orderId) {
//procure tokens
procureTokens(tokenIn, amountIn, recipient, permit, permitPayload);
//construct and store order
orderId = MASTER.generateOrderId(recipient);
orders[orderId] = Order({
orderId: orderId,
tokenIn: tokenIn,
tokenOut: tokenOut,
amountIn: amountIn,
minAmountOut: minAmountOut,
- recipient: recipient,
feeBips: feeBips
});
//store pending order
pendingOrderIds.push(orderId);
emit OrderCreated(orderId);
}
function createOrder(
IERC20 tokenIn,
IERC20 tokenOut,
uint256 amountIn,
uint256 minAmountOut,
uint16 feeBips,
bool permit,
bytes calldata permitPayload
) external override returns (uint96 orderId) {
//procure tokens
procureTokens(tokenIn, amountIn, recipient, permit, permitPayload);
//construct and store order
orderId = MASTER.generateOrderId(recipient);
orders[orderId] = Order({
orderId: orderId,
tokenIn: tokenIn,
tokenOut: tokenOut,
amountIn: amountIn,
minAmountOut: minAmountOut,
+ recipient: msg.sender,
feeBips: feeBips
});
//store pending order
pendingOrderIds.push(orderId);
emit OrderCreated(orderId);
}
- Implement a nonce when generating the
orderId
to prevent order replacement. https://github.com/sherlock-audit/2024-11-oku/blob/main/oku-custom-order-types/contracts/automatedTrigger/AutomationMaster.sol#L90
- function generateOrderId(address sender) external view override returns (uint96) {
uint256 hashedValue = uint256(
- keccak256(abi.encodePacked(sender, block.timestamp))
);
return uint96(hashedValue);
}
+ uint256 private nonce;
... ... ...
+ function generateOrderId(address sender) external override returns (uint96) {
uint256 hashedValue = uint256(
+ keccak256(abi.encodePacked(sender, block.timestamp, ++nonce))
);
return uint96(hashedValue);
}