Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Invalid

[H-5] `NFTLiquidator` auctions can be permanently DoS with malicious receiver contract that always reverts

Summary

When an NFT is liquidated it will be sent from the StabilityPool to the NFTLiquidator contract and a 3 days auction will start. Users can bid for the NFT via the placeBid function or buy it directly via buyBackNFT. The current design of the auction is to store the current highestBidder address and if a new user bids more, the protocol attempts to repay the previous highestBidder before overriding it.

The problem with this approach is that the whole auction system can be DoSed by placing a bid from a smart contract that implements a receive() function that always reverts. When the placeBid or buyBackNFT functions attempt to repay the previous highestBidder, the transaction will always revert and users are unable to place bids anymore. The auction system is permanently DOSed. The current design mimics almost perfectly the Ethernaut CTF level 09 King.

Vulnerability Details

The crux of the attack relies on the assumption that the previous highestBidder will always be successfully refunded. Since the NFTLiquidator contract attempts to transfer tokens to the previous highestBidder if this address is a smart contract that implements a receive() function that always reverts, transferring tokens to that smart contract won't work, which will lead to reverting transactions. Check the code below

function placeBid(uint256 tokenId) external payable {
//..
//..
//@audit this transfer will always fail if `highestBidder` is a smart contract that doesn't receive tokens
if (data.highestBidder != address(0)) {
payable(data.highestBidder).transfer(data.highestBid);
}
//..
}

also here we have the same logic

function buyBackNFT(uint256 tokenId) external payable {
//..
//..
//@audit this transfer will always fail if `highestBidder` is a smart contract that doesn't receive tokens
if (data.highestBidder != address(0)) {
payable(data.highestBidder).transfer(data.highestBid);
}
//..
//..
}

Attack path

  1. A malicious user creates a smart contract with a receive() function that always reverts.

  2. The attacker monitors liquidations and immediately bids a very small amount of tokens, say for example 0.000000001 tokens on each new auction.

  3. Since the attacker's contract is now the highestBidder subsequent user bids will always revert, DoSing the auctions permanently.

Impact

  1. The whole auction system can be permanently DoS.

  2. NFTs will remain locked in the NFTLiquidator contract

Tools Used

Manual review

Recommendations

The refund logic for previous bidders needs an overhaul. I suggest storing the amounts that each previous highestBidder is entitled to in a mapping of address -> unit, and after the auction ends, allow each user to claim their tokens back.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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