AuctionDemo.sol
- Winner can get NFT for free
#1152
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-1323
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104-L145
Vulnerability details
Impact
The logic of Auction can be summarized by describing 3 functions:
participateToAuction()
- user bids.cancelBid()
/cancelAllBids()
- user cancels his bid(s).claimAuction()
- when auction ends, winner receives NFT.The vulnerability in above implementation is caused by improper definition of Auction duration.
Winner of the auction can call
claimAuction()
to receive the NFT, and then, immediately callcancelBid()
/cancelAllBids()
to get the refund of their bid. This will result in getting NFT for free.Proof of Concept
File: AuctionDemo.sol
File: AuctionDemo.sol
File: AuctionDemo.sol
cancelBid()
andcancelAllBids()
can be called only whenblock.timestamp <= minter.getAuctionEndTime(_tokenid)
claimAuction()
can be called only whenblock.timestamp >= minter.getAuctionEndTime(_tokenid)
This implies, that both
cancelBid()
,cancelAllBids()
,claimAuction()
can be called whenblock.timestamp == minter.getAuctionEndTime(_tokenid)
claimAuction()
andcancelBid()
(orcancelAllBids()
) in the same block whereblock.timestamp == minter.getAuctionEndTime(_tokenid)
.claimAuction()
executes, it transfers NFT to the user. Please notice thatclaimAuction()
does not changeauctionInfoData[_tokenid][i].status
. It's set totrue
even after the NFT claim.cancelBid()
(orcancelAllBids()
) executes. Sinceblock.timestamp == minter.getAuctionEndTime(_tokenid)
andstatus
is stilltrue
, bid is being cancelled and refunded:File: AuctionDemo.sol
Winner called
claimAuction()
andcancelBid()
in the same block, whereblock.timestamp == minter.getAuctionEndTime(_tokenid)
. This allows him to get NTF (claimAuction()
) and get the refund (cancelBid()
) afterwards.Tools Used
Manual code review
Recommended Mitigation Steps
There are multiple of ways to resolve this issue.
(1)
claimAuction()
should be called whenblock.timestamp > minter.getAuctionEndTime(_tokenid)
Please notice that when we change
>=
to>
, it won't be possible to callclaimAuction()
andcancelBid()
/cancelAllBids()
during the sameblock.timestamp
.(2)
claimAuction()
should change thestatus
after the NFT transferWhen NFT is transferred,
auctionInfoData[_tokenid][i].status
should be changed tofalse
.That way, it won't be possible to call
cancelBid()
orcancelAllBids()
- since those functions requireauctionInfoData[_tokenid][i].status
to betrue
.Please make sure to set this
status
before performingIERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
to avoid any risk of reentrancy.Assessed type
Other
The text was updated successfully, but these errors were encountered: