Platform: Code4rena
Start Date: 30/10/2023
Pot Size: $49,250 USDC
Total HM: 14
Participants: 243
Period: 14 days
Judge: 0xsomeone
Id: 302
League: ETH
Rank: 205/243
Findings: 1
Award: $0.00
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: smiling_heretic
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0x656c68616a, 0xAadi, 0xAleko, 0xAsen, 0xDetermination, 0xJuda, 0xMAKEOUTHILL, 0xMango, 0xMosh, 0xSwahili, 0x_6a70, 0xarno, 0xgrbr, 0xpiken, 0xsagetony, 3th, 8olidity, ABA, AerialRaider, Al-Qa-qa, Arabadzhiev, AvantGard, CaeraDenoir, ChrisTina, DanielArmstrong, DarkTower, DeFiHackLabs, Deft_TT, Delvir0, Draiakoo, Eigenvectors, Fulum, Greed, HChang26, Haipls, Hama, Inference, Jiamin, JohnnyTime, Jorgect, Juntao, Kaysoft, Kose, Kow, Krace, MaNcHaSsS, Madalad, MrPotatoMagic, Neon2835, NoamYakov, Norah, Oxsadeeq, PENGUN, REKCAH, Ruhum, Shubham, Silvermist, Soul22, SovaSlava, SpicyMeatball, Talfao, TermoHash, The_Kakers, Toshii, TuringConsulting, Udsen, VAD37, Vagner, Zac, Zach_166, ZdravkoHr, _eperezok, ak1, aldarion, alexfilippov314, alexxander, amaechieth, aslanbek, ast3ros, audityourcontracts, ayden, bdmcbri, bird-flu, blutorque, bronze_pickaxe, btk, c0pp3rscr3w3r, c3phas, cartlex_, cccz, ciphermarco, circlelooper, crunch, cryptothemex, cu5t0mpeo, darksnow, degensec, dethera, devival, dimulski, droptpackets, epistkr, evmboi32, fibonacci, gumgumzum, immeas, innertia, inzinko, jasonxiale, joesan, ke1caM, kimchi, lanrebayode77, lsaudit, mahyar, max10afternoon, merlin, mrudenko, nuthan2x, oakcobalt, openwide, orion, phoenixV110, pontifex, r0ck3tz, rotcivegaf, rvierdiiev, seeques, shenwilly, sl1, slvDev, t0x1c, tallo, tnquanghuy0512, tpiliposian, trachev, twcctop, vangrim, volodya, xAriextz, xeros, xuwinnie, y4y, yobiz, zhaojie
0 USDC - $0.00
The auctionDemo contract enables users to cancel and withdraw any bid that they previously made, including the current highest bid. This means that a user can make a completely out of market bid completely discouraging other users from bidding again (eg: if an NFT from a collection is worth on average 10, they can bid for 50) and than cancel the bid at the last second, meaning that the auction will be virtually unavailable for the vast majority of the time.
This opens up for following scenarios:
As the auction start a user can bid an out of market amount, wait till the last few seconds, than cancel the bid, preventing the majority of users from participating in the auction, likely getting the item sold for a discounted price, as the time left for bidding will be minimum.
As the auction start a user can bid an out of market amount, wait till the last few seconds, than cancel the bid, than places a very low bid and (even 1 wei, if possible), if afterwards there is no time left (or extremely little) they might get the item for the specified extremely cheap price.
An artist can artificially pump the price of their assets, without incurring in any risk, as they can always withdraw their highest bid (even if no one surpass them), to let the one immediately below win (frontrunnig withdraws if necessary).
A validator knowing that they will mine blocks around the auction's end timestamp, can do the same trick of bidding extremely high, cutting away any competition, and then both delete the bid an create a new one, inside the block where the timestamp is equal to the end of the auction, getting the NFT at an artificially discounted price.
-1,2,3)
The auctionDemo contract, which enables NFT to be auctioned, has a cancelBid function, that lets users delete a bid and withdraw correspondent ETH:
function cancelBid(uint256 _tokenid, uint256 index) public { require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true); auctionInfoData[_tokenid][index].status = false; (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}(""); emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid); }
As can be seen this function only checks that:
-block.timestamp <= minter.getAuctionEndTime(_tokenid)
, the auction hasn't ended.
-auctionInfoData[_tokenid][index].bidder == msg.sender
, msg.sender is the one who placed the bid.
-uctionInfoData[_tokenid][index].status == true
and that the bid has not been already withdrawn.
This means that even the highest bid can be withdrawn, since there is no restriction against it, enabling
the scenarios listet in Impact
.
-4) As can be observed the checks against the auction's end performed by participateToAuction, cancelBid and claimAuction, the three functions necessary to place a new bid, delete an old one, and claim the price, are all performed using <=
or >=
:
function participateToAuction(uint256 _tokenid) public payable { require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
function cancelBid(uint256 _tokenid, uint256 index) public { require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
Meaning that they can all three be invoked in the same block for as long as block.timestamp == minter.getAuctionEndTime(_tokenid)
, enabling scenario 4, in the impact
session
the cancelBid function could check that the bid that is being deleted, isn't the currently highest bid
Other
#0 - c4-pre-sort
2023-11-15T10:47:44Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-02T15:13:22Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-02T15:17:13Z
alex-ppg marked the issue as duplicate of #1784
#3 - c4-judge
2023-12-07T11:49:31Z
alex-ppg marked the issue as duplicate of #1323
#4 - c4-judge
2023-12-08T17:27:25Z
alex-ppg marked the issue as partial-50
#5 - c4-judge
2023-12-08T17:28:24Z
alex-ppg marked the issue as satisfactory
#6 - c4-judge
2023-12-08T18:24:25Z
alex-ppg marked the issue as partial-50
#7 - c4-judge
2023-12-09T00:20:29Z
alex-ppg changed the severity to 3 (High Risk)