It is possible for users to bid and unbid within the same block that the auction ends. If an attacker deposits points after the auction has ended, the tokens will be distributed incorrectly, benefiting the attacker and preventing others from claiming their share of the tokens.
The bid and unbid functions check if block.timestamp > auctionEndTime
, while the auctionEnd
function checks if block.timestamp < auctionEndTime
. In cases where block.timestamp
is equal to auctionEndTime
, both checks are ignored, allowing these functions to be executed in any order.
Suppose an attacker ends the auction when block.timestamp
is exactly auctionEndTime
and places a bid immediately afterward. Because the auction has already ended, the tokens to points ratio (multiplier
) cannot be updated anymore. When the attacker then calls claimTokens
, the old multiplier
is used along with the new userBid
. This allows the attacker to claim more tokens than intended and blocks other users from claiming because the contract no longer holds sufficient tokens.
The following PoC demonstrates a scenario where one user block others from claiming tokens by depositing points without effecting the multiplier
variable.
One user receives more tokens than intended, while others are potentially blocked from claiming their share.
Manual Review, Foundry
Disable ending the auction while adding and removing bids is still allowed by simply reverting auctionEnd
when the current block timestamp is less than or equal to auctionEndTime
:
Alternatively, you can adjust the comparison operators in bid()
and unbid()
or check the ended
variable in these functions.
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.