Bid Beasts

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

Incorrect Auction Duration Implementation

Description

The contract implements a 15-minute auction duration instead of the specified 3-day duration from the README documentation. This creates a critical mismatch between the documented specification and actual implementation.

Location: BidBeastsNFTMarketPlace.sol:34, 154

README Specification:

  • "Auction deadline of exactly 3 days" (line 57)

  • "After 3 days, anyone can call endAuction(toke·nId)" (line 41)

Current Implementation:

uint256 constant public S_AUCTION_EXTENSION_DURATION = 15 minutes;
// First bid sets auction to end in 15 minutes, not 3 days
listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;

Risk

Severity: High

Likelihood: High - This affects every auction in the system

Impact:

  • Core functionality doesn't match documented behavior (288x shorter duration)

  • Auctions can be extended indefinitely through continuous bidding

  • Users expect 3 days to participate but only get 15-minute windows

  • Malicious actors can prevent auctions from ending by bidding every 14 minutes

  • Legitimate bidders miss opportunities due to extremely short timeframes

  • settleAuction() instead of documented endAuction()

Proof of Concept

Infinite Extension Attack:

// Attacker can extend auction indefinitely
function attackInfiniteExtension(uint256 tokenId) external payable {
// Place minimal bid increase every 14 minutes
market.placeBid{value: currentBid * 105 / 100}(tokenId);
// This extends auction by another 15 minutes
// Repeat forever to lock NFT permanently
}

Duration Mismatch Test:

function test_auctionDurationMismatch() public {
_mintNFT();
_listNFT();
// Place first bid
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE + 0.1 ether}(TOKEN_ID);
BidBeastsNFTMarket.Listing memory listing = market.getListing(TOKEN_ID);
// Should be 3 days (259200 seconds) but is only 15 minutes (900 seconds)
uint256 expectedEnd = block.timestamp + 3 days;
uint256 actualEnd = listing.auctionEnd;
assertEq(actualEnd, block.timestamp + 15 minutes); // Currently passes (wrong)
// assertEq(actualEnd, expectedEnd); // Should pass but fails
}

Recommended Mitigation

Implement proper auction duration constants and logic:

// Separate base duration from anti-sniping extension
uint256 constant public S_AUCTION_DURATION = 3 days;
uint256 constant public S_ANTI_SNIPE_EXTENSION = 15 minutes;
uint256 constant public S_MAX_AUCTION_DURATION = 5 days; // Prevent infinite extensions
// First bid sets 3-day duration
if (previousBidAmount == 0) {
listing.auctionEnd = block.timestamp + S_AUCTION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
} else {
// Anti-sniping logic with maximum duration cap
if (timeLeft < S_ANTI_SNIPE_EXTENSION &&
listing.auctionEnd + S_ANTI_SNIPE_EXTENSION <= block.timestamp + S_MAX_AUCTION_DURATION) {
listing.auctionEnd = listing.auctionEnd + S_ANTI_SNIPE_EXTENSION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}
}

Also rename settleAuction() to endAuction() to match the documentation.

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!