Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

Missing Auction Deadline Enforcement delays Auction settlement

Root + Impact

Description

The BidBeastsNFTMarket contract does not enforce a fixed auction deadline of exactly 3 days, despite the claim that it supports an "auction deadline of exactly 3 days." Instead, the contract implements an auction extension mechanism that can indefinitely extend the auction duration with each new bid.

In this implementation, the contract sets the auction end time to only 15 minutes after the first bid and then keeps extending the auction by another 15 minutes if a bid arrives close to the deadline. There is no hard 3-day cutoff, meaning the auction can continue indefinitely as long as new bids keep arriving within the extension window.

// Root cause in the codebase with @> marks
if (previousBidAmount == 0) {
listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION; // @> only 15 min, not 3 days
emit AuctionExtended(tokenId, listing.auctionEnd);
} else {
if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION; // @> indefinite rolling extension
emit AuctionExtended(tokenId, listing.auctionEnd);
}
}

Risk

Likelihood:

Occurs on every auction that receives bids.

Triggered whenever new bids arrive near the auction’s end.

Impact:

Auction does not end in 3 days, contrary to expectations.

Auctions can be prolonged indefinitely, delaying settlement and payouts.

Bidders and sellers cannot rely on a predictable closing time, which can harm user trust.

Proof of Concept

function test_AuctionExtendsWithNewBids() external {
_mintNFT();
_listNFT();
// First bid starts the auction
vm.prank(BIDDER_1);
market.placeBid{value: 2e18}(TOKEN_ID);
// Check initial auction end time (15 minutes from now)
uint256 initialEnd = market.getListing(TOKEN_ID).auctionEnd;
assertEq(initialEnd, block.timestamp + 15 minutes, "Auction should start with 15-minute duration");
// Fast forward to 10 minutes before end
vm.warp(block.timestamp + 5 minutes); // 10 minutes remain
vm.prank(BIDDER_2);
uint256 secondBidAmount = ( 2e18 / 100) * (100 + 5);
market.placeBid{value: secondBidAmount}(TOKEN_ID);
// Check if auction extended
uint256 newEnd = market.getListing(TOKEN_ID).auctionEnd;
assertEq(newEnd, initialEnd + 15 minutes, "Auction should extend by 15 minutes");
// Verify auction cannot be settled yet
vm.expectRevert("Auction has not ended");
market.settleAuction(TOKEN_ID);
}
}

Recommended Mitigation

- listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
+ listing.auctionEnd = block.timestamp + 3 days;
- if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
- listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
- emit AuctionExtended(tokenId, listing.auctionEnd);
- }
+ if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
+ uint256 maxEnd = listing.auctionStart + 3 days;
+ uint256 newEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
+ listing.auctionEnd = newEnd > maxEnd ? maxEnd : newEnd;
+ emit AuctionExtended(tokenId, listing.auctionEnd);
+ }

Alternatively, enforce a strict 3-day auction deadline without extensions, you can modify the contract to set auctionEnd to block.timestamp + 3 days on the first bid and remove the extension logic.

+ uint256 constant public S_AUCTION_DURATION = 3 days;
function placeBid(uint256 tokenId) external payable isListed(tokenId) {
Listing storage listing = listings[tokenId];
address previousBidder = bids[tokenId].bidder;
//other codes
+ require(listing.auctionEnd == 0 || block.timestamp < listing.auctionEnd, "Auction ended");
}
Updates

Lead Judging Commences

cryptoghost Lead Judge
2 months ago
cryptoghost Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeasts Marketplace: Improper Documentation

Documentation for BidBeasts Marketplace is incomplete or inaccurate, potentially leading to misconfigurations or security misunderstandings.

Support

FAQs

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

Give us feedback!