In the FjordAuction contract, the auction has a defined end time, stored in the state variable auctionEndTime. Users are allowed to place and withdraw bids until block.timestamp reaches this specified end time. Once this point is reached, anyone can call the auctionEnd() function to finalize the auction. After the auction is finalized, users can claim their auction tokens based on their bids.
However, the current implementation has a vulnerability: users can call auctionEnd() to end the auction and then place additional bids afterwards.
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L143
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L159
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L181
bid() and auctionEnd() have the corresponding checks to see if auction has ended based on the current block.timestamp
Neither the bid() nor the unbid(), nor auctionEnd() functions explicitly check if the current block.timestamp is exactly equal to auctionEndTime. Since the block.timestamp is set by the block miner, it can be adjusted to match the auctionEndTime.
Malicious user could exploit the situation by executing auctionEnd() followed by bid() , claimTokens() and unbid() in the same transaction. During the auctionEnd() call, a multiplier is calculated based on the total bids at that moment. This multiplier is later used to determine the claimable rewards.
This scenario leads to two issues:
The malicious user can obtain a more favorable ratio for their Fjord Points by bidding after auctionEnd() has been called, thereby manipulating the calculated multiplier. This results in an unfair distribution of rewards. Additionally, the malicious user can then withdraw his fjord points by unbid().
After the malicious user claims their auction tokens, the contract may not have enough tokens left to distribute to other legitimate bidders. This imbalance could cause a DoS situation, as other bidders would be unable to claim their rewards until the contract is replenished with additional tokens by the admin.
As described in the Vulnerability Details section, the impact is unfair distribution of auction tokens and limited DoS.
Manual Review.
Update the checks inside bid() and unbid() functions to also check the ended variable.
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.