This report details a critical vulnerability discovered FjordAuction::auctionEnd and FjordAuction::bid functions, which could allow an attacker to manipulate the auction process and prevent other bidders from claiming their auction tokens. The issue arises due to improper timing checks in both functions, which create a narrow window of opportunity for exploitation.
bid Function: This function allows users to place bids for auction tokens using points.
auctionEnd Function: This function finalizes the auction, calculating the multiplier that determines the number of auction tokens each bidder can claim based on their points bid.
Timing Checks
auctionEnd Function Check: The function includes a condition that checks if block.timestamp is less than auctionEndTime. If true, the function reverts, meaning the auction cannot be finalized before the designated end time.
bid Function Check: The function includes a condition that checks if block.timestamp is greater than auctionEndTime. If true, the function reverts, preventing bids from being placed after the auction has ended.
Logic Flaw
The issue arises due to the following sequence of events:
At exactly auctionEndTime, both the auctionEnd and bid functions could be invoked in the same block.
The auctionEnd function would pass the condition for the revert block.timestamp < auctionEndTime and proceed to calculate the multiplier based on the bids placed up to that point.
Immediately after, an attacker could invoke the bid function in the same block. Given the precise timing, this function would also pass its condition for revert block.timestamp > auctionEndTime and allow the attacker to place a bid.
The attacker's bid would not be accounted for in the multiplier calculation, but they would still be able to claim auction tokens as if their bid were valid, effectively siphoning the auction tokens away from legitimate bidders.
User 1 bids
User 2 bids
Attacker calls auctionEnd() and Bid(totalBids) in the same block @ auctionEndTime
User 1 and User 2 lose their points and the auction tokens.
Attack Contract
Lock Out Other Bidders: Since the auction multiplier has already been calculated, if the attacker bids the totalBids amount, other legitimate bidders would be unable to claim their tokens, leading to potential financial loss.
Manual Review
Change the check in the bid function from block.timestamp > auctionEndTime to block.timestamp >= auctionEndTime.
The protocol doesn't properly treat the `block.timestamp == auctionEndTime` case. Impact: High - There are at least two possible impacts here: 1. By chance, user bids could land in a block after the `auctionEnd()` is called, not including them in the multiplier calculation, leading to a situation where there are insufficient funds to pay everyone's claim; 2. By malice, where someone can use a script to call `auctionEnd()` + `bid(totalBids)` + `claimTokens()`, effectively depriving all good faith bidders from tokens. Likelihood: Low – The chances of getting a `block.timestamp == auctionEndTime` are pretty slim, but it’s definitely possible.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.