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: 135/243
Findings: 4
Award: $3.39
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: btk
Also found by: 00xSEV, 0x175, 0x180db, 0x3b, 0xAlix2, 0xJuda, 0xpiken, 0xraion, 3th, 836541, Al-Qa-qa, AvantGard, Aymen0909, Beosin, ChrisTina, DarkTower, DeFiHackLabs, EricWWFCP, Kose, Kow, KupiaSec, MrPotatoMagic, Neo_Granicen, PENGUN, PetarTolev, Ruhum, Soul22, SovaSlava, SpicyMeatball, Talfao, The_Kakers, Toshii, Tricko, VAD37, Viktor_Cortess, ZdravkoHr, _eperezok, alexxander, audityourcontracts, ayden, bird-flu, bronze_pickaxe, codynhat, critical-or-high, danielles0xG, degensec, droptpackets, evmboi32, fibonacci, flacko, gumgumzum, ilchovski, immeas, innertia, jacopod, joesan, ke1caM, kk_krish, mojito_auditor, nuthan2x, phoenixV110, pontifex, r0ck3tz, sces60107, seeques, sl1, smiling_heretic, stackachu, t0x1c, trachev, turvy_fuzz, ubl4nk, ustas, xAriextz, xuwinnie, y4y
0.152 USDC - $0.15
The identified vulnerability allows a user to exceed the prescribed token minting limit during the allowlist phase. If this user is the first to initiate minting during this phase and possesses sufficient capital, they can exploit this flaw to mint the entire available token supply from the collection.
A user gains allowlist access for minting a limited number of tokens from a new collection, utilizing a smart contract address for the allowlist. He invokes the MinterContract#mint method to start minting.
Here we jump into the first condition block because we are in the first phase. One important require block is here to check whether _maxAllowance is higher or equal to retrieveTokensMintedALPerAddress (Number of tokens minted by address during the first phase) + _numberOfTokens (Number of tokens user wants to mint). The user is allowed to mint limited number of tokens so this condition should fail when he tries to mint more. The retrieveTokensMintedALPerAddress method returns value from NextGenCore tokensMintedAllowlistAddress state variable that keeps track of how many tokens have been minted to an address.
require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
When this condition is passed, it gets to a for loop that calls NextGenCore#mint to process a token mint.
for(uint256 i = 0; i < _numberOfTokens; i++) { uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col); gencore.mint(mintIndex, mintingAddress, _mintTo, tokData, _saltfun_o, col, phase); }
The root cause of this vulnerability lies here in the NextGenCore mint method. As you can see, it mints the token before it updates the count of tokens minted by address. This violates Checks-Effects-Interactions pattern and opens paths for reentrancy attacks.
function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external { require(msg.sender == minterContract, "Caller is not the Minter Contract"); // @note Update circulating supply collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1; if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) { // @note Mint token to user using safeMint. _mintProcessing(mintIndex, _mintTo, _tokenData, _collectionID, _saltfun_o); // @audit-issue Checks-Effects-Interactions pattern broken. The count of minted tokens should be updated before the token is minted. if (phase == 1) { tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1; } else { tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1; } } }
When we check the _mintProcessing function we find out that it uses _safeMint method. This opens the attack path because the user wants the token to be minted to a smart contract address. Safe mint calls IERC721Receiver.onERC721Received in the recipient contract.
function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal { tokenData[_mintIndex] = _tokenData; collectionAdditionalData[_collectionID].randomizer.calculateTokenHash(_collectionID, _mintIndex, _saltfun_o); tokenIdsToCollectionIds[_mintIndex] = _collectionID; _safeMint(_recipient, _mintIndex); }
The user can use this callback to reenter the MinterContract#mint method and start the process again. There is the require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
condition that should revert the transaction as we describe at the beginning. But he reentered the method before the number of minted tokens was updated. Because of it, the user is able to mint as many tokens as he wants to up to the maximum supply if he has enough ether. He just need to reenter the mint method from the onERC721Received callback.
Manual review
I recommend fixing the NextGenCore#mint method by applying the C-E-I pattern or you may consider adding a reentrancy guard.
function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external { require(msg.sender == minterContract, "Caller is not the Minter Contract"); collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1; if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) { - _mintProcessing(mintIndex, _mintTo, _tokenData, _collectionID, _saltfun_o); if (phase == 1) { tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1; } else { tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1; } + _mintProcessing(mintIndex, _mintTo, _tokenData, _collectionID, _saltfun_o); } }
Reentrancy
#0 - c4-pre-sort
2023-11-20T13:29:23Z
141345 marked the issue as duplicate of #1597
#1 - c4-pre-sort
2023-11-26T14:00:18Z
141345 marked the issue as duplicate of #1742
#2 - c4-judge
2023-12-08T16:24:07Z
alex-ppg marked the issue as satisfactory
#3 - c4-judge
2023-12-08T16:24:41Z
alex-ppg marked the issue as partial-50
#4 - c4-judge
2023-12-08T19:17:08Z
alex-ppg marked the issue as satisfactory
🌟 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
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L105 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L125 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L135
When the block.timestamp equals the auction end time, both the claimAuction and cancelBid functions can be invoked. This creates a scenario where the winning bidder can abuse the situation to profit by claiming an NFT and reentering the cancelBid function to retrieve their Ether, essentially obtaining the NFT for free. Additionally, other active bidders may also reenter the cancelBid function from their smart contracts to exploit the reentrancy vulnerability and gain Ether equal to the value of their bids. The situation becomes more severe when multiple auctions occur in the same contract, potentially draining Ether from other token auctions.
The vulnerability arises due to overlapping conditions in the claimAuction, cancelBid, and cancelAllBids functions. All of these functions can be invoked when block.timestamp == minter.getActionEndTime(_tokenId).
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); // ... } function cancelBid(uint256 _tokenid, uint256 index) public { require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); // ... } function cancelAllBids(uint256 _tokenid) public { require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); // ... }
The claimAuction method is responsible for transferring the ERC721 token to the winner and refunding bids to other participants. It provides a reentrancy point through the safeTransferFrom call and low-level calls using payable(address).call{value:...}(""). These mechanisms enable users to easily reenter the contract.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); auctionClaim[_tokenid] = true; // ... for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid); // @audit-issue reentrancy (bool success, ) = payable(owner()).call{value: highestBid}(""); emit ClaimAuction(owner(), _tokenid, success, highestBid); } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); // @audit-issue reentrancy emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid); } else {} } }
Both the cancelBid and cancelAllBids functions lack reentrancy protection and do not check for the condition auctionClaim[_tokenid] == false as is done in the claimAuction method.
Active bidders can exploit this vulnerability during the auction claim when block.timestamp equals the auction end time. This is facilitated by the absence of checks for the success of low-level function calls in the auction contract, which prevents transactions from reverting due to a lack of Ether in the contract.
Manual review
I strongly recommend eliminating the existing overlaps between conditions.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ - require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); + require(block.timestamp > minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); // ... }
Reentrancy
#0 - c4-pre-sort
2023-11-14T15:42:37Z
141345 marked the issue as duplicate of #289
#1 - c4-pre-sort
2023-11-14T23:32:16Z
141345 marked the issue as duplicate of #962
#2 - c4-judge
2023-12-04T21:40:25Z
alex-ppg marked the issue as duplicate of #1323
#3 - c4-judge
2023-12-08T18:17:12Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: The_Kakers
Also found by: 00xSEV, 0xAsen, 0xDetermination, 0xJuda, 0xWaitress, 0xhunter, 0xlemon, 0xpiken, Al-Qa-qa, Arabadzhiev, CSL, CaeraDenoir, DarkTower, DeFiHackLabs, Greed, Haipls, MaNcHaSsS, NentoR, NoamYakov, PENGUN, Ruhum, Soul22, SovaSlava, Talfao, Toshii, TuringConsulting, VAD37, Vagner, Valix, Viktor_Cortess, ZdravkoHr, audityourcontracts, btk, codynhat, flacko, funkornaut, glcanvas, gumgumzum, immeas, innertia, ke1caM, lanrebayode77, lsaudit, mrudenko, niki, nmirchev8, openwide, oualidpro, r0ck3tz, rvierdiiev, trachev, yojeff
2.7688 USDC - $2.77
The vulnerability allows any participant, especially a malicious actor, to engage in a Denial of Service (DoS) attack on the auction claim functionality. By backrunning the auction creation and strategically participating in the bidding process, the attacker can exhaust the gas of the claim initiator, resulting in a transaction revert and locking the funds of other bidders in the auction contract.
The vulnerability arises in the claimAuction function, particularly in the bidding process where there is no gas limit set for the return of bids to participants. The lack of a gas limit enables a malicious participant to spend all the gas of the claim initiator, leading to a DoS attack.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { // ... } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); // @audit-issue no gas limit // ... } else {} } }
The sequence of events leading to the DoS attack involves the creation of the auction, strategic bidding by the attacker, and the subsequent invocation of the claimAuction function:
Hacker has to use multiple bids because of EIP150. Since this proposal, the gas sent to external calls is 63/64 of gas left.
Also, even with the gas limit in place, there is still a way to do the gas grieving. Hacker may use the receive method in his contract to return enormous data payload which is then saved to the memory. Writing (bool success, )
is the same as (bool success, bytes memory data)
. Memory allocation becomes very costly and a huge amount of gas will be spent for allocating data to memory.
A proof of concept has been developed using Remix to demonstrate how gas depletion occurs. The attacker exploits the absence of a gas limit, causing the transaction to fail due to an out-of-gas error.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "hardhat/console.sol"; contract Auction { struct Bid { address bidder; uint bid; } Bid[] public bidInfo; function claim() public { for (uint i; i < bidInfo.length; i++) { console.log("Return bid number:", i + 1); console.log("| Gas before external call:", gasleft()); (bool success,) = payable(bidInfo[i].bidder).call{value: bidInfo[i].bid}(""); console.log("| Gas after external call:", gasleft()); } } function participate() public payable { Bid memory newBid = Bid(msg.sender, msg.value); bidInfo.push(newBid); } } contract GasGriefer { uint public counter; constructor(address auction) payable { for (uint i; i < 4; i++) { Auction(auction).participate{value: i + 1}(); } } receive() external payable { counter = 0; while (true) { counter++; } } }
The result is that the transaction fails because of an out-of-gas error. The attacker paid only 10 wei to spend all the maximum gas in the block and brick the auction.
console.log: Return bid number: 1 | Gas before external call: 29972904 | Gas after external call: 467942 Return bid number: 2 | Gas before external call: 465525 | Gas after external call: 6928 Return bid number: 3 | Gas before external call: 4510 transact to Auction.claim errored: Error occured: out of gas.
In case you think that this is a duplicate of the issue reported in bot race by Hound, Permanent DoS due to non-shrinking array usage in an unbounded loop, let me explain why this issue is different.
Yes, the impact is similar - gas grieving and DoS of auction claim. But the root causes and solutions aren't the same and solving one won't solve the other. Hound's issue is based on growing the size of the array indefinitely. The transaction will revert because of iterating through the "infinitely" long array. Vulnerability I found doesn't depend on the growing array. All I need are three bids to DoS the claim and it's because of the missing gas limit.
Manual review
To address this vulnerability, the following mitigation steps are highly recommended:
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ // ... for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { // ... } else if (auctionInfoData[_tokenid][i].status == true) { - (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); + (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid, gas: GAS_LIMIT}(""); emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid); } else {} } }
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ // ... for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { // ... } else if (auctionInfoData[_tokenid][i].status == true) { - (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); + bool success; + address bidder = auctionInfoData[_tokenid][i].bidder; + uint bid = auctionInfoData[_tokenid][i].bid; + assembly { + success := call(GAS_LIMIT, bidder, bid, 0, 0, 0, 0) + } emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid); } else {} } }
DoS
#0 - c4-pre-sort
2023-11-20T13:29:46Z
141345 marked the issue as duplicate of #486
#1 - c4-judge
2023-12-01T22:45:09Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-01T22:45:38Z
alex-ppg marked the issue as duplicate of #1782
#3 - c4-judge
2023-12-08T20:53:55Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: The_Kakers
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0xJuda, 0x_6a70, 0xarno, 0xpiken, Arabadzhiev, Bauchibred, BugsFinder0x, BugzyVonBuggernaut, ChrisTina, DeFiHackLabs, Delvir0, HChang26, Haipls, Jiamin, Juntao, KupiaSec, Madalad, Neon2835, Nyx, Ocean_Sky, SpicyMeatball, Talfao, Taylor_Webb, Timenov, Tricko, ZdravkoHr, _eperezok, alexxander, amaechieth, bdmcbri, bronze_pickaxe, circlelooper, crunch, cu5t0mpeo, dimulski, fibonacci, funkornaut, immeas, ke1caM, lsaudit, nuthan2x, r0ck3tz, rotcivegaf, spark, tnquanghuy0512, twcctop, xeros
0.4703 USDC - $0.47
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L112 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L125 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L135
If the winning bidder in the auction contract does not implement the IERC721Receiver#onERC721Received method, the execution of the claimAuction() function will revert because of ERC721#_checkOnERC721Received. As a result, bidders will be unable to retrieve their funds after the auction period ends.
Bidders may call 3 methods to participate in the auction or cancel their bid.
When you investigate those functions they share a require block. They can be called only when the block.timestamp is lower or equal to the auction end time. Because of that the bidders can't add bids or withdraw their funds after the auction end.
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 cancelAllBids(uint256 _tokenid) public { require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); // ... }
Logic for returning ether to non-winners is in the claimAuction method. This function goes through all the bids and returns them. For the winning bid it tries to transfer the token to winner using safeTransferFrom function. Here lies the vulnerability.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ // ... for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid); (bool success, ) = payable(owner()).call{value: highestBid}(""); // ... } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); // ... } else {} } }
In the event that the winning bidder is another smart contract, it must implement the onERC721Received method. Failure to do so results in a transaction revert, leaving the ether used for bidding on a specific token trapped in the contract because participants can't cancel their bids nor send new higher bid to change the winner.
This vulnerability poses a significant risk, as it opens the door for malicious users to launch a Denial of Service (DoS) attack on the contract, effectively locking up a substantial amount of ether. Consider a scenario in which a popular token is being auctioned, and approximately 100 participants place bids. If bids range from 10,000 to 10,099, the total value locked in the contract could reach 1,004,950. An attacker would only need to spend 10,100 to render this amount inaccessible, resulting in a potential loss of approximately 1% of the total value.
Moreover, there is the risk of unintentional contract bricking if the winning bidder forgets to implement the required onERC721Received method.
Manual review
To address this vulnerability, remove the require statements in the cancelBid and cancelAllBids functions to allow bidders to cancel their bids after auction end.
function cancelBid(uint256 _tokenid, uint256 index) public { - require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); // ... } function cancelAllBids(uint256 _tokenid) public { - require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); // ... }
DoS
#0 - c4-pre-sort
2023-11-15T08:55:55Z
141345 marked the issue as duplicate of #843
#1 - c4-pre-sort
2023-11-16T13:35:53Z
141345 marked the issue as duplicate of #486
#2 - c4-judge
2023-12-01T22:50:15Z
alex-ppg marked the issue as not a duplicate
#3 - c4-judge
2023-12-01T22:50:44Z
alex-ppg marked the issue as duplicate of #1759
#4 - c4-judge
2023-12-08T22:16:16Z
alex-ppg marked the issue as partial-50
#5 - c4-judge
2023-12-09T00:23:13Z
alex-ppg changed the severity to 2 (Med Risk)