A medium severity vulnerability has been identified in the FjordAuction contract. There is a potential timing conflict between the bid
/unbid
functions and the auctionEnd
function when block.timestamp
is exactly equal to auctionEndTime
. This could lead to unexpected behavior, potential unfairness in the auction process, and possible manipulation of the auction's final state.
The vulnerability stems from the timing conditions in the bid
, unbid
, and auctionEnd
functions:
For bid
and unbid
:
For auctionEnd
:
When block.timestamp == auctionEndTime
, all three functions can be called within the same block. This creates a race condition where the order of transactions in the block becomes crucial:
If auctionEnd
is called first, it will set ended = true
, preventing any further bids or unbids.
If bid
or unbid
is called first, it will allow last-second changes to the auction state before it ends.
This inconsistency can lead to unfair advantages or disadvantages for participants depending on transaction ordering within the block.
The impact of this vulnerability includes:
Potential for Unfair Advantage: Users who can manipulate transaction ordering might be able to place or withdraw bids after seeing the final state of the auction.
Inconsistent Auction End State: The final state of the auction could vary depending on which function is executed first in the critical block.
User Confusion and Dissatisfaction: Participants might expect to be able to bid until the last second, but find their transactions reverted if auctionEnd
is called first.
Possible Loss of Funds or Opportunities: Users attempting to place last-second bids might have their transactions fail unexpectedly, potentially leading to missed opportunities or gas costs without effect.
Manipulation of Auction Outcome: In extreme cases, this could be exploited to manipulate the auction's outcome, especially if large bids or unbids are made in the final moments.
Manual
To address this vulnerability, we recommend modifying the auctionEnd
function to make the auction end time exclusive. This ensures a clear and unambiguous end to the bidding period. Here's the suggested modification:
This change accomplishes the following:
It creates a clear distinction between the bidding period and the auction end.
It allows bids and unbids to occur up to and including the auctionEndTime
.
The auction can only be ended after the auctionEndTime
has passed.
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 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.