Bid Beasts

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

Integer division allows minimum bid increment requirement to be bypassed with small bids.

Root + Impact

Description

  • Normal Behavior: A new bid should be at least 5 higher than the previous bid, as defined by S_MIN_BID_INCREMENT_PERCENTAGE.

  • Specific Issue: The calculation for the minimum required subsequent bid uses integer division: (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE). This logic truncates the fractional part when dividing previousBidAmount by 100. For small previousBidAmount values, this truncation dramatically reduces the required increment, allowing the new bid to be only slightly more than the previous one, thus bypassing the intended 5 increase.


Example: If previousBidAmount is 104 wei, 104/100 is 1 (integer division). The requiredAmount becomes 1×105=105 wei. This means the user only needed to increase the bid by 1 wei (105−104), far less than the intended 5.2 wei.

// Root cause in the codebase with @> marks to highlight the relevant section
requiredAmount = (@> previousBidAmount / 100 <@) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE);

Risk

Likelihood:

  • The flaw is guaranteed to manifest for any bid amount not divisible by 100.

  • This occurs frequently for low-value bids, where precision is most critical.

Impact:

  • Auction Integrity Flaw. Undermines the integrity of the auction rules, allowing malicious users to game the bidding system with minimal financial commitment.

Proof of Concept

This PoC demonstrates a previous bid of 104 wei only requiring a 1 wei increment, instead of the 5 minimum.

function test_exploit_bidIncrementBypass() public {
// Set S_MIN_BID_INCREMENT_PERCENTAGE = 5
// Assume we have an auction where previousBidAmount = 104 wei
// The flawed calculation: (104 / 100) * 105 = 1 * 105 = 105 wei
uint256 previousBidAmount = 104;
uint256 requiredAmount = (previousBidAmount / 100) * 105;
// The correct minimum bid should be 104 * 1.05 = 109.2 (or 110 wei, rounding up)
// Assert: The actual required increase is only 1 wei (105 - 104)
assertEq(requiredAmount - previousBidAmount, 1, "Required increment is too low, bypassing 5%");
assertLt(requiredAmount, 110, "Required amount should be at least 110 (rounded 5% up)");
}

Recommended Mitigation

The order of operations must be changed to perform multiplication before division to prevent truncation. This preserves precision and ensures the required percentage increase is met.

- requiredAmount = (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE);
+ // FIX: Multiply first to prevent precision loss from integer division
+ requiredAmount = (previousBidAmount * (100 + S_MIN_BID_INCREMENT_PERCENTAGE)) / 100;
require(msg.value >= requiredAmount, "Bid not high enough");
Updates

Lead Judging Commences

cryptoghost Lead Judge 29 days ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeasts Marketplace: Integer Division Precision Loss

Integer division in requiredAmount truncates fractions, allowing bids slightly lower than intended.

Support

FAQs

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