The timestamp sanity checks at the FjordAuction contract allow a malicious user to bid after an auction has ended. This leads to an inflated claim eligibility for the user and to auction insolvency.
The auctionEnd function requires the block timestamp must be at least equal to the auction's end time. Then it sets the multiplier variable based on the total amount of bids.
The bid function requires the block timestamp is at most equal to the auction's end time, but doesn't check if the auction is already over by verifying the boolean value of the ended
variable:
If a malicious party calls both auctionEnd and bid sequentially via a single transaction in the moment when block.timestamp equals auctionEndTime, then this user will be able to place a bid after the auction is over and the multiplier is computated.
Since this multiplier was calculated taking into account an X amount of bids that did not account this malicious party's bids, the claiming logic becomes insolvent:
Let us have an auction with 1k Fjord points worth of bids and a total tokens worth 10k USDC.
Alice calls the auction end and bids 1k Fjord points.
The multiplier would be 10k USDC * PRECISION_18 / 1k Fjord points.
Alice then claims the tokens and the other bidders end up left empty handed.
Malicious parties could use this vulnerability to make auctions insolvent.
This specific order of operations allows legitimate bidders to have a diluted token claims.
Manual review
Make sure to check the ended
boolean variable in order to allow bids, unbids and claims. If the ended value is false, only bids and unbids should be open. If the ended
value is true, only claims should be open.
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.