Core Contracts

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

Zero Starting Bid Vulnerability

Summary

When an NFT is liquidated, the highestBid is initialized to 0, allowing the first bidder to place an extremely low bid (e.g., 1 wei) as long as it exceeds 0 plus the minimum bid increase percentage. This vulnerability could result in NFTs being sold at prices far below their associated debt or market value, undermining the financial recovery process for the StabilityPool and potentially leading to exploitation by malicious actors.

Vulnerability Details

The vulnerability originates in the liquidateNFT function, where the highestBid for an auction is initialized to 0:

tokenData[tokenId] = TokenData({
debt: debt,
auctionEndTime: block.timestamp + 3 days,
highestBid: 0, // Vulnerability: Starting bid is 0
highestBidder: address(0)
});

In the placeBid function, the contract enforces that each new bid must exceed the current highestBid plus a minimum increase percentage (minBidIncreasePercentage):

uint256 minBidAmount = data.highestBid + (data.highestBid \* minBidIncreasePercentage / 100);
if (msg.value <= minBidAmount) revert BidTooLow(minBidAmount);
  • Initial Condition: When the auction begins, highestBid is 0.

  • First Bid Calculation: For a minBidIncreasePercentage of 10%, the minimum bid amount is calculated as 0 + (0 * 10 / 100) = 0. Thus, any bid greater than 0 (e.g., 1 wei) is accepted as the first bid.

  • Unfair Auction Outcomes: Legitimate participants may be deterred from engaging in auctions where NFTs are consistently won at negligible prices, reducing trust in the system.

Impact

The StabilityPool, which relies on auction proceeds to recover the debt associated with liquidated NFTs, may receive far less than the debt amount. For example, an NFT with a 1 ETH debt could theoretically be won for a few wei if bidding competition is low.

Recommendations

function liquidateNFT(uint256 tokenId, uint256 debt) external {
if (msg.sender != stabilityPool) revert OnlyStabilityPool();
nftContract.transferFrom(msg.sender, address(this), tokenId);
uint256 startingBid = debt * 50 / 100; // 50% of debt as starting bid
tokenData[tokenId] = TokenData({
debt: debt,
auctionEndTime: block.timestamp + 3 days,
highestBid: startingBid,
highestBidder: address(0)
});
indexToken.mint(stabilityPool, debt);
emit NFTLiquidated(tokenId, debt);
emit AuctionStarted(tokenId, startingBid, tokenData[tokenId].auctionEndTime);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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

Give us feedback!