xanoutas/solidity-security-findings huggingface dataset:
DoS in ‘ claimAuction() ’  function if an address maliciously reverts while receiving refund.
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L104-L120


# Vulnerability details

## Impact

A malicious address can place a trivial bid and perform a DoS attack by reverting while receiving the refund.

## Proof of Concept

Adam = Attacker

Adam places a trivial bid of 69 wei at the start of the auction from a contract that is designed to 
revert when receiving ether.

```
receive() external payable {
        
        revert("Reverting: I'm malicious ");
}

```

When the auction eventually ends and the ` claimAuction() ` function is called by either the winner or Admin,
The refunds and NFT transfer dont happen as expected. 

Because Adam's contract reverts upon receiving the refund 
thus creating a Denial of Service for all bidders involved.

This can be averted by preferring 'pull over push' pattern for withdrawals / refunds.


## Tools Used

Manual Review, Foundry.

## Recommended Mitigation Steps

Enforce 'pull over push' design pattern for withdrawals / refunds, 
as it is more secure and flexible.
It allows users or external contracts to withdraw funds on their own initiative.
This way a DoS attack could be prevented.





## Assessed type

DoS
Admin can become owner of NextGenAdmins.sol and drain funds of the protocol.
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L454-L457
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/RandomizerRNG.sol#L61-L64
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L322-L325


# Vulnerability details

## Impact
A function/global admin can call the `updateAdminContract()` function found in NextGenCore.sol, MinterContract.sol, RandomizerRNG.sol contracts to implement a new NextGenAdmins.sol contract by easily passing the following check `require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");` all they have to do is include the following function in their new contract. Implementing a new NextGenAdmins.sol contract this way makes the function/global admin owner of the new contract, allowing them to call `emergencyWithdraw()` function and draining the funds of the MinterContract.sol.

```solidity
function isAdminContract() external view returns (bool) {
        return true;
    }
```

From contacting the developer team and confirming it, function admins should have less rights than global admins but with this vulnerability they can get the full rights of a global admin/owner.

Impact of this vulnerability is critical since it leads to loss of all funds.

This vulnerability leads to a function admin making themselves a global admin and owner of NextGenAdmins.sol. This function admin can now call many functions that they shouldn’t have access to. This works for every function that a global admin has access to, essentially being able to call most of the important functions. Even if function admin and global admin are trusted with these functions they can still make themselves the owner of NextGenAdmins.sol. 

Being a trusted role is not an excuse for function admin/global admin to have this kind of access to drain funds from the contract since something as simple as this function admin getting fired from the developer team and calling the function before they are removed from the admin pool can cause them to act maliciously.

## Proof of Concept
A potential attack can happen with the steps shown below. 
1) A user(let’s call it Alice) gets added as a function admin of `updateAdminContract()` function either by a mistake or on purpose, when a global admin calls the `registerFunctionAdmin()`function in NextGenAdmins.sol ([line #44-46](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenAdmins.sol#L44-L46))

2) Alice calls `updateAdminContract()` function in MinterContract.sol ([line #454-457](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L454-L457)) by passing a new contract as the parameter and including `isAdminContract()` functio
The malicious participant can perform a DOS attack on the claimAuction function using 1 wei ETH
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L116


# Vulnerability details

## Bug Description
In order to participate in the auction, the `participateToAuction` function must be called with the higher bid than previous one, and to claim the NFT, one should invoke the `claimAuction` function. The `claimAuction` function includes logic for refunding ETH to users who did not win the auction. If one of the users participating in the auction is malicious, ETH may be permanently locked in the `auctionDemo` smart contract:
```solidity
(bool success, ) = payable(auctionInfoData[_tokenid][i].bidder)
                    .call{value: auctionInfoData[_tokenid][i].bid}("");
                emit Refund(
                    auctionInfoData[_tokenid][i].bidder,
                    _tokenid,
                    success,
                    highestBid
                );
```

## Proof-of-Concept
Let's consider the following scenario:

`Note`: Currently, low-level calls don't check return values. However, the logic for claiming NFT and refund must be separated. This issue will arise after returned value checks are implemented.

1. A malicious participant joins the auction with a bid of 1 wei.
2. The auction ends with the highest bid being 5 ETH.
3. When the `claimAuction` is called, the transaction will fail if the malicious participant is a smart contract that lacks a `receive` function.

## Impact
The ETH used to participate in the auction will be locked.

## Tools Used
Manual

## Recommended Mitigation Steps
Consider separating the logic for claiming NFT and refund in the auctionDemo smart contract.



## Assessed type

DoS
Cross-function reentrancy allows the attacker to claim the same bid twice. 
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104-L120


# Vulnerability details

## Impact
AuctionDemo::claimAuction() allows the claiming the token with highest bid. The Winner or admin both can call the function once the auction ends or the block.timestamp `>=` to auction end time. The issue is claim and cancel function can be call at exactly at the same timestamp, which is auctionEndTime. 

A malicious bidder can bid as highest to be winner, and then perform claim call followed by bidder(as malicious contract) fallback trigger followed by cancelBid() on the auction contract, all at the same timestamp the auction end. 

And because the we are not checking `success` value for other bidders fund transfer, it allows the attacker to steal their funds without reverting.  

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L116

## Proof of Concept
1. Alice saw the auction, wait for the last seconds before auction ends. 
2. Alice frontrun any `participateToAuction` call, with highest possible amount(not greater than other bidder combine bid amount). 
3. Alice became highest bidder, and when `block.timestamp == minter.getAuctionEndTime(_tokenid)` reached, alice as malicious bidder perform call to claimAuction() -> malicious bidder contract -> cancelBid(). 

Alice manage to claim the highest amount she bid, also stealing others bid amount. 

## Tools Used
Manual review

## Recommended Mitigation Steps
Use reentrancy guard to avoid reentrancy, cancelBid() and participateToAuction() should only be called for the timestamp < minter.getAuctionEndTime(_tokenId). 


## Assessed type

Reentrancy
Potential vulnerable to readonly-reentrancy function.
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L343-L357
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L409-L411
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L450-L457


# Vulnerability details

## Impact
the function tokenURI is a view function that reads the state variable _owners from the inherited contract ERC721. This variable stores the mapping from token ID to owner address. However, this variable can be modified by other functions such as _safeMint and _burn, which are called after external calls to other contracts. This means that the value of _owners can change during the execution of tokenURI, and the function can return an incorrect or outdated URI for the token.

## Proof of Concept
Potential vulnerable to readonly-reentrancy function (if read in other function) NextGenCore.tokenURI(uint256) (smart-contracts/NextGenCore.sol#343-357):
State variables read that were written after the external call(s):
- ERC721._owners (smart-contracts/ERC721.sol#31) was read at _requireMinted(tokenId) (smart-contracts/NextGenCore.sol#344)
This variable was written at (after external call):
- _safeMint(_recipient,_mintIndex) (smart-contracts/NextGenCore.sol#231)
- _burn(_tokenId) (smart-contracts/NextGenCore.sol#220)
- ERC721._owners (smart-contracts/ERC721.sol#31) was read at onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000 (smart-contracts/NextGenCore.sol#345)
This variable was written at (after external call):
- _safeMint(_recipient,_mintIndex) (smart-contracts/NextGenCore.sol#231)
- _burn(_tokenId) (smart-contracts/NextGenCore.sol#220)
- ERC721._owners (smart-contracts/ERC721.sol#31) was read at baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI (smart-contracts/NextGenCore.sol#346)
This variable was written at (after external call):
- _safeMint(_recipient,_mintIndex) (smart-contracts/NextGenCore.sol#231)
- _burn(_tokenId) (smart-contracts/NextGenCore.sol#220)
- ERC721._owners (smart-contracts/ERC721.sol#31) was read at onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000 (smart-contracts/NextGenCore.sol#348)
This variable was written at (after external call):
- _safeMint(_recipient,_mintIndex) (smart-contracts/NextGenCore.sol#231)
- _burn(_tokenId) (smart-contracts/NextGenCore.sol#220)
- ERC721._owners (smart-contracts/ERC721.sol#31) was read at baseURI_scope_0 = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI (smart-contracts/NextGenCore.sol#349)
This variable was written at (after external call):
- _safeMint(_recipient,_mintIndex) (smart-contracts/NextGenC
User can participate, claim and cancel all his bids in one block
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L58
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


# Vulnerability details

## Bug Description
The `auctionDemo` smart contract has three functions responsible for the NFT auction. All these functions, `participateToAuction, claimAuction, and cancelBid`, lack reentrancy checks and can be called when `block.timestamp == minter.getAuctionEndTime()`, meaning at the same time.

## Proof-of-Concept
The `participateToAuction, cancelBid, and claimAuction` functions can be called in the last second of the auction:
```solidity
block.timestamp <= minter.getAuctionEndTime(_tokenid)
block.timestamp >= minter.getAuctionEndTime(_tokenid)
```

Additionally, there are no reentrancy checks in the aforementioned functions, and low-level calls are not checked for success.

Let's consider the following scenario:

Grouping all the aforementioned issues, we have the following scenario:
`Preconditions`: There are two different auctions for NFT with id 1, the highest bid being 3 ETH, and for NFT with id 2, the highest bid being 5 ETH.

1.	A malicious user participates with a small bid (1 wei) in the auction for NFT id - 1.
2.	Other users also participate in the auction, and the highest bid reaches 3 ETH.
3.	In the last second of the auction, the malicious user rebids for the auction with NFT 1 with a bid of 4 ETH, executes `claimAuction` and `cancelBid` in the same transaction. Additionally, other users may also `cancelBid` in the same block, even after a refund in the `claimAuction` function.

## Impact
The user can obtain the NFT and claim ETH for participating.

## Tools Used
Manual

## Recommended Mitigation Steps
Consider changing `claimAuction` as follows:
```diff
function claimAuction(
        uint256 _tokenid
    ) public WinnerOrAdminRequired(_tokenid, this.claimAuction.selector) {
        require(
-            block.timestamp >= minter.getAuctionEndTime(_tokenid) &&
+            block.timestamp > minter.getAuctionEndTime(_tokenid) &&
                auctionClaim[_tokenid] == false &&
                minter.getAuctionStatus(_tokenid) == true
        );

		///code
}
```


## Assessed type

Invalid Validation
Permanent freeze of funds after auction end, if token owner does not approve the token
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104-L120
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L111


# Vulnerability details

## Impact
In a possible case, when the owner of an auction token decides not to send his token to the highest bidder, they will have just not to approve the token to be transferred by the Auction contract. Even though the situation above is a common practice, the Auction contract lacks the functionality to return funds to all the bidders. Instead, bids stay locked permanently or until the token owner decides to approve the transfer. 

## Proof of Concept
1. The admin of `MinterContract.mintAndAuction` function mints and auctions the token for Alice.
2. Bobby places the highest bid on Alice's token
3. After the auction time ends, Bobby, as the auction winner, calls `claimAuction`. However, the function call would fail as Alice hasn't approved the token and does not intend to. Furthermore, NextGen admins cannot approve it for Alice due to the ERC721 functionality.
4. Bobby wants to get his funds back from the auction contract. However, both `cancelBid` and `cancelAllBids` would fail because the auction has ended. As a result, Bobby's funds would be frozen in the contract either until Alice approves the token or permanently.
[AuctionDemo.sol#L104-L120](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104-L120)


In order to test this, make sure to deploy the auction contract in `fixturesDeployment.js` and create a new test file as `hardhat/test/POCs.test.js`:


```js
  File: hardhat/test/POCs.test.js

const {
    loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { expect } = require("chai");
const { ethers } = require("hardhat");
const fixturesDeployment = require("../scripts/fixturesDeployment.js");
const { time } = require('@nomicfoundation/hardhat-network-helpers'); // for POCs

let signers;
let contracts;

describe("Proof of Concept", function () {
    before(async function () {
        ({ signers, contracts } = await loadFixture(fixturesDeployment));
    });

    context("Permanent Freeze of Bids", () => {

        before("#dataWereAdded", async function () {
            // create collection_1
            await contracts.hhCore.createCollection(
                "Test Collection 1",
                "Artist 1",
                "For testing",
                "www.test.com",
                "CCO",
                "https://ipfs.io/ipfs/hash/",
                "",
                ["desc"]
            );

            // set collection_1 data
            await contracts.hhCore.setCollectionData(
                1, // _collectionID
                signers.addr1.address, // _collectionArtistAddress
                2, // _maxCollectionPurchases
Reentrancy in `NextGenMinterContract.mint()` allows exceeding max allowance and concurrent use of NFTs in `NextGenMinterContract.burnToMint()`
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/2467db02cc446374ab9154dde98f7e931d71584d/smart-contracts/MinterContract.sol#L213
https://github.com/code-423n4/2023-10-nextgen/blob/2467db02cc446374ab9154dde98f7e931d71584d/smart-contracts/MinterContract.sol#L217
https://github.com/code-423n4/2023-10-nextgen/blob/2467db02cc446374ab9154dde98f7e931d71584d/smart-contracts/MinterContract.sol#L224


# Vulnerability details

## Impact
1. **Bypassing `_maxAllowance` in `NextGenMinterContract.mint()`**: Enables minting more NFTs than permitted.
2. **Exploiting reentrancy in `NextGenMinterContract.burnToMint()`**: Allows acquiring both burnable and mintable NFTs at the same time.

## Proof of Concept
### The 1st case
The typical flow of a user mint is as follows:
User tx -> `NextGenMinterContract.mint()` external call -> `NextGenCore.mint()` internal call -> `NextGenCore._mintProcessing()`

The root of the problem lies in the `NextGenCore.mint()` and `NextGenCore._mintProcessing()` functions.

```solidity
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;
        }
    }
}

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);
}
```

In the `mint()` function, the `_mintProcessing()` is called first and then the variables `tokensMintedAllowlistAddress` or `tokensMintedPerAddress` are updated. However, this creates a reentrancy issue because the `_safeMint()` at the end of `_mintProcessing()` calls `_recipient.onERC721Received()`.

`_recipient` can be either the user or his chosen delegate, so passing a smart contract is not a problem.

To take advantage o
collection admin can still change delegation Address by calling setCollectionCosts()
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/hardhat/smart-contracts/MinterContract.sol#L164

# Vulnerability details

## Impact

Function updateDelegationCollection() which update allowlist mint
delegation collection prevents collection admin and any other actors from
perfoming this except global and Function Admin.

However, collection admin can still change delegation Address by calling
setCollectionCosts()

## Proof Of Concept

setCollectionCosts():

```solidity
function setCollectionCosts(uint256 _collectionID, uint256
_collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256
_timePeriod, uint8 _salesOption, address _delAddress) public
CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
        require(gencore.retrievewereDataAdded(_collectionID) == true, "Add
data");
        collectionPhases[_collectionID].collectionMintCost =
_collectionMintCost;
        collectionPhases[_collectionID].collectionEndMintCost =
_collectionEndMintCost;
        collectionPhases[_collectionID].rate = _rate;
        collectionPhases[_collectionID].timePeriod = _timePeriod;
        collectionPhases[_collectionID].salesOption = _salesOption;
        collectionPhases[_collectionID].delAddress = _delAddress; // @audit
        setMintingCosts[_collectionID] = true;
    }
```

As you can see, this gives collection admin access to change delegation
Address as well

## Tools Used

Visual Studio Code

## Recommended Mitigation Steps

update changing delegation address to be only accessed by the global and
Function Admin with only updateDelegationCollection()

```diff
function setCollectionCosts(uint256 _collectionID, uint256
_collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256
_timePeriod, uint8 _salesOption, address _delAddress) public
CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
        require(gencore.retrievewereDataAdded(_collectionID) == true, "Add
data");
        collectionPhases[_collectionID].collectionMintCost =
_collectionMintCost;
        collectionPhases[_collectionID].collectionEndMintCost =
_collectionEndMintCost;
        collectionPhases[_collectionID].rate = _rate;
        collectionPhases[_collectionID].timePeriod = _timePeriod;
        collectionPhases[_collectionID].salesOption = _salesOption;
-       collectionPhases[_collectionID].delAddress = _delAddress;
        setMintingCosts[_collectionID] = true;
    }
```

## Assessed type

Access Control