DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: medium
Valid

Attackers can drain the auction tokens from bidders when block.timestamp == auctionEndTime

Summary

when block.timestamp == auctionEndTime, attackers can end auction, bid large amount and then claim, draining the auction tokens from bidders

Vulnerability Details

Context:
FjordAuction.sol#L182

In the FjordAuction.sol, the bid() and unbid() can execute as long as the current time is not past the auction end time:

function bid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
...

this means when the block.timestamp == auctionEndTime it will still be executed. The issue here is that the auctionEnd() function can also be executed when block.timestamp == auctionEndTime:

function auctionEnd() external {
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}

As seen above it only checks if it's less than but doesn't handle when it's == auctionEndTime, therefore when block.timestamp == auctionEndTime this allows an attacker to end an auction which then set the multiplier,:

multiplier = totalTokens.mul(PRECISION_18).div(totalBids);

call the bid function to bid in a large amount, and then claim all the tokens using the claimTokens() function all in a single transaction. draining the auction tokens from bidders seen attacker bid wasn't included in the totalBid used in the multiplier calculations.

Impact

Attackers can drain the auction tokens from bidders

Tools Used

Manaul Review

Recommendations

Ensure both bid/unbid and auctionEnd can't be called at the same time. Set one of these to handle when block.timestamp == auctionEndTime. E.g

function auctionEnd() external {
+ if (block.timestamp <= auctionEndTime) {
- if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Users can bid in the same block when the actionEnd could be called (`block.timestamp==actionEndTime`), depending on the order of txs in block they could lose funds

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.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.