xanoutas/solidity-security-findings huggingface dataset:
AuctionDemo opens itself several DoS attack vectors 
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

## Proof of Concept
The `auctionDemo.auctionInfoData` map holds important info on auctions, and hold this info per tokenId. Needless to say, for many auctions that may become popular and/or long running, the `auctionInfoStru[]` array for a given `_tokenid` can get very large.

`mapping (uint256 => auctionInfoStru[]) public auctionInfoData;`

There are several methods in this contract involve core logic that loops through the whole `auctionInfoStru[]` array for a tokenId. If this array is sufficiently large enough, then the transaction that called any of the methods that directly invoke or indirectly rely on this looping logic can easily run out of gas and thus fail. In order to retry again and have the transaction success, it might require a huge amount of gas which can be very expensive.

The following function directly invoke or indirectly rely on looping through `auctionInfoData[_tokenid]`, where _tokenid is any given token being auctioned, which could very easily have potentially large length, enough so for a tx to run out of gas:
- participateToAuction
- returnHighestBid
- returnHighestBidder
- claimAuction 
- cancelAllBids   

This is essentially all the major functions of the NextGen auction functionality.

Some more details on the issues:
- `returnHighestBid` is widely used; any function that calls this is subject to potential tx failure if the loop through bids is large enough, which could happen quite often
- if an `Admin` calls `claimAuction` to reward winners and there was a sufficiently large enough amount of bidders, the tx to refund everyone and reward the winner will either fail or require a HUGE amount of gas to assure the tx finishes to completion; if `Winner` calls, they face the same issue rewarding themselves rightfully. 

## Tools Used
Solidity 

## Recommended Mitigation Steps
Pull model over push model -> Require Winners seeking their rightful prize and losers seeking refund to manually refund themselves; this can easily be implemented with a map lookup instead of large for loops.


## Assessed type

DoS
Missing deadline checks
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L461


# Vulnerability details

Consider addings implementation to handle the expiration of the transaction for additional security.

To implement a transaction expiration mechanism in the `emergencyWithdraw` add a timestamp check to ensure that the transaction is executed only within a certain timeframe. This can be achieved by introducing a state variable to store the deadline and then checking against this deadline within the function.

First, you would introduce a state variable and a function to set the deadline. This could be set when the emergency situation is declared or when the contract is initialized.

```solidity
uint256 public withdrawalDeadline;

function setWithdrawalDeadline(uint256 _deadline) public onlyOwner {
    withdrawalDeadline = _deadline;
}
```

Here, `onlyOwner` should be a modifier that allows only the contract owner to set the deadline. The `_deadline` would typically be a timestamp in Unix time.

Then, modify the `emergencyWithdraw` function to check against this deadline:

```solidity
function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) noReentrant {
    require(block.timestamp <= withdrawalDeadline, "Transaction expired");

    uint balance = address(this).balance;
    address admin = adminsContract.owner();
    require(admin != address(0), "Admin address is zero");

    uint256 gasLimit = someGasLimit; // Define according to your contract's requirements

    (bool success, ) = payable(admin).call{value: balance, gas: gasLimit}("");
    emit Withdraw(msg.sender, success, balance);
}
```

In this setup, the `emergencyWithdraw` function will fail if the current block timestamp is later than the `withdrawalDeadline`. This prevents the function from being called after the specified deadline, adding an extra layer of security and control over the emergency withdrawal process. 

Remember, when setting the deadline, ensure the timestamp is in the future and reasonable based on the expected timeframe for the emergency situation. Also, be aware of the time zone considerations when working with timestamps in Solidity, as they are in UTC.



## Assessed type

Invalid Validation
Missing gas fee limit
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L461


# Vulnerability details

The use of .call{value: balance}("") does not limit the gas sent along with the Ether, potentially allowing all gas in the transaction to be used by the receiver.

```solidity
// Set a specific gas limit for the call (if applicable)
    uint256 gasLimit = someGasLimit; // Define according to your contract's requirements

    (bool success, ) = payable(admin).call{value: balance, gas: gasLimit}("");
    emit Withdraw(msg.sender, success, balance);
```



## Assessed type

Invalid Validation
AuctionDemo::claimAuction() - L105: Logic bug in the conditional statement where the timestamp check should be `>` instead of `>=`.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/a6f2397b68ef2865374c1bf7629349f25e71a44d/smart-contracts/AuctionDemo.sol#L105


# Vulnerability details

## Impact

- Would enable the winning bidder/bid to be selected WHILE it's still possible to bid (higher) in the auction. I.e. current comparison logic makes it possible to select auction winner while the auction isnt over yet.
- there's the risk of the true/valid highest bidder not getting the NF

## Proof of Concept

If it's still unclear, let me clarify from a different perspective:
Auction duration is from 0 to 10, lets say.
We can only select auction winner AFTER the auction (duration). This means `> 10`, NOT `>= 10`.
If we wanted to make 10 valid for auction winner selection, then we would need to make auction duration from 0 to 9, where the auction ends at 9. Now we can have `>= 10` which is logically correct.

## Tools Used
VSC. Manual.

## Recommended Mitigation Steps

```diff
- 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);
```



## Assessed type

Other
Cross-Contract Reentrancy can occur during burnToMint
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L218-L220


# Vulnerability details

## Impact
Cross Contract re-entrancy can occur due to not following CEI 

## Proof of Concept

1. Attacker can call burnToMint(), with any of the tokenId he owns! 
2. This calls the `burnToMint` in GenCore, which mints the the new token from the to be minted collection.

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L218-L220
```
_mintProcessing(mintIndex, ownerOf(_tokenId), tokenData[_tokenId], _mintCollectionID, _saltfun_o);
// burn token
_burn(_tokenId);  
```
3. The issue that the protocol is minting the newToken and calling the receiver, without first burning the tokens. This allows the attacker to sell the tokens if it had liquidity and the token will get burned in the same transaction leading to the party who received token at the loss.




## Tools Used

## Recommended Mitigation Steps
Tokens should be burned before minting and calling the receiver contract, this follows the safe pattern

```
// burn token
_burn(_tokenId);  
_mintProcessing(mintIndex, ownerOf(_tokenId), tokenData[_tokenId], _mintCollectionID, _saltfun_o);

```



## Assessed type

Reentrancy
Missing Reentry Protection in 'emergencyWithdraw' function
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L461


# Vulnerability details

Ensure that all state changes in `emergencyWithdraw` are done before the external `call` to prevent reentrancy attacks. The function is vulnerable to reentrancy attacks due to the use of .call{value: balance}(""). This can be mitigated by adding a reentrancy guard.-

 **Poc:**
```solidity
contract Malicious {
    VulnerableContract public vulnerableContract;

    constructor(address _vulnerableContractAddress) {
        vulnerableContract = VulnerableContract(_vulnerableContractAddress);
    }

    // Fallback function used to receive Ether and re-enter emergencyWithdraw
    receive() external payable {
        if (address(vulnerableContract).balance >= msg.value) {
            vulnerableContract.emergencyWithdraw();
        }
    }

    function attack() external payable {
        require(msg.value > 0, "Send ETH to attack");
        vulnerableContract.emergencyWithdraw();
    }

    function withdraw() external {
        payable(msg.sender).transfer(address(this).balance);
    }
}

```



## Assessed type

Reentrancy
Add reentrancy protection in `payArtist` function
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L415


# Vulnerability details

In `payArtist` function, the potential for reentrancy exists due to the `call` method being used to transfer Ether. The `call` method is known to be risky for reentrancy attacks because it hands off control to the called contract, which could be malicious. After the Ether transfer via `call`, if there is more code executing that modifies the contract's state, it might be vulnerable to reentrancy.

```solidity
contract Malicious {
    address payable public target;
    uint256 public drainCount = 0;

    constructor(address payable _target) {
        target = _target;
    }

    // Fallback function invoked when Ether is received
    receive() external payable {
        if (drainCount < 3) { // Prevents infinite loop, adjust based on the attack scenario
            drainCount++;
            YourContract(target).payArtist(/* parameters */);
        }
    }

    function attack() external payable {
        // Call payArtist with appropriate parameters
        YourContract(target).payArtist(/* parameters */);
    }

    function withdraw() external {
        payable(msg.sender).transfer(address(this).balance);
    }
}

```
**Mitigation**

```solidity
function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) noReentrant {
    // Function logic...
}
```




## Assessed type

Reentrancy
`burnToMint` and `burnOrSwapExternalToMint` allows bypass of periodic sales timer.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L258-L272
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L326-L365


# Vulnerability details

## Description

Sales Mode 3 is when the contract allows only one mint per period of time. However, `burnToMint` and `burnOrSwapExternalToMint` allows an user to bypass this restriction, since these functions don't have periodic sales check. This can be a problem since these sales mode collection tend to have higher prices, since the circulation supply will be lower. 

## Proof of Concept 

1. These functions don't have any periodic sales checks: 
```solidity
    function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
        require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
        require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
        require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error");
        // minting new token
        uint256 collectionTokenMintIndex;
        collectionTokenMintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID);
        require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_mintCollectionID), "No supply");
        require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH");
        uint256 mintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID);
        // burn and mint token
        address burner = msg.sender;
        gencore.burnToMint(mintIndex, _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o, burner);
        collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
    }

 function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
        bytes32 externalCol = keccak256(abi.encodePacked(_erc721Collection,_burnCollectionID));
        require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
        require(setMintingCosts[_mintCollectionID] == true, "Set Minting Costs");
        address ownerOfToken = IERC721(_erc721Collection).ownerOf(_tokenId);
        if (msg.sender != ownerOfToken) {
            bool isAllowedToMint;
            isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
Artist Royalty Split Proposal Functionality Missing
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/tree/main/smart-contracts/MinterContract.sol#L369


# Vulnerability details

## Impact
The protocol's documentation specifies that royalty splits can be proposed by the artist and accepted by the admin. However, the `MinterContract` does not implement the functionality for artists to propose royalty splits. This inconsistency between the documentation and the actual implementation impacts the protocol's functionality.
![Royalty Splits Proposal](https://github.com/hungdoo/public-assets/blob/main/royalties-splits.png?raw=true "")

## Proof of Concept
The root cause of the vulnerability is that the protocol's `MinterContract` does not include the functionality for artists to propose royalty splits as specified in the documentation. This impacts the overall functionality and can lead to misunderstandings and misalignment of expectations among users.

## Tools Used
Manual Review

## Recommended Mitigation Steps
To address this issue, it is recommended to implement the propose/accept mechanism for royalty PrimaryAndSecondarySplits data, as specified in the documentation. This will align the actual implementation with the documented protocol behavior and prevent potential confusion among users.

## References
- [Protocol Documentation](https://seize-io.gitbook.io/nextgen/nextgen-smart-contracts/features)
- [Royalty Splits Proposal (Image)](https://github.com/hungdoo/public-assets/blob/main/royalties-splits.png)


## Assessed type

Other
Bid's array can be overloaded with dust bids to break AuctionDemo funcionality.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L69
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L136
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L110
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L90


# Vulnerability details

## Description

Bids to the auction can be created using any `msg.value` via `participateToAuction` method and are stored in an array within the mapping `auctionInfoData`. However, all important methods (`claimAuction`, `returnHighestBid`, `returnHighestBidder`, `participateToAuction`) loops through the array, which can allow an attacker to fulfill it with numerous dust valueless bids to cause these functions to revert due to out of gas errors. In the worst case, where he can't overload the array enough, he will still impact other users since they will be potentially spending more gas (more money) than expected.

## Proof of Concept 

1. An auction has just started.
2. Attacker calls `participateToAuction` as much as he can:
```solidity
    function participateToAuction(uint256 _tokenid) public payable {
        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
        auctionInfoStru memory newBid = auctionInfoStru(msg.sender, msg.value, true);
        auctionInfoData[_tokenid].push(newBid);
    }
```
- Every single call executes `auctionInfoData[_tokenid].push(newBid);`, increasing the length of the bid's array.

3. The function requires `msg.value` to be higher than the highestBid. However, a new auction won't have any bid, so the attacker just needs to increment 1 wei in each `participateToAuction` call. 
4. After he called it enough times, essential functions like `participateToAuction` will try to loop through `auctionInfoData[_tokenid]`, but will spend enough gas to revert or make the transaction a lot more expensive than it should, which impacts any user of the protocol. 

## Impact

Attacker can interrupt an auction or make every function call a lot more expensive.

1. Likelihood: Low. Attacker needs to do in starts of auction and a non-dust bid can revert the attack, since new bids need to be the highest price of the array.
2. Impact: High. Attacker can make every user overspend gas values and potentially revert the whole protocol, which doesn't have any emergency withdraw function.
- Risk: Medium (Low Likelihood with High Impact) 

## Tools Used 

Manual Review 

## Recommended Mitigation Steps 

Define a minimum value check in `participateAuction`. After that, any attack like this will have a high cost. 


## Assessed type

Loop
Unchecked constructor arguments can make a contract unworkable
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L132,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L109,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/RandomizerNXT.sol#L27,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/RandomizerRNG.sol#L32,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/RandomizerVRF.sol#L44,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L39


# Vulnerability details

## Impact
In the `NextGenCore` contract constructor, there is no check that a valid admin contract is set using `NextGenAdmins::isAdminContract()`.

If the contract address in the `_adminsContract` constructor is set incorrectly, it is not possible to call admin functions in the contract, which will cause the contract to become inoperable.

It is impossible to change the address of the contract after deployment, because `NextGenCore::updateAdminContract()` uses the `FunctionAdminRequired()` modifier, which calls the current admin contract. But since we have it specified incorrectly, it is impossible to access its functions.

This leads to the problem that if you initially set an incorrect address, it is impossible to change it later. The functions cannot be performed from the admin role.

This problem is found in contracts:
- NextGenCore.sol
- RandomizerVRF.sol
- MinterContract.sol
- NextGenRandomizerNXT
- AuctionDemo.sol
- NextGenRandomizerRNG.sol



## Proof of Concept
Deployer specifies the wrong contract address in the constructor argument `_adminsContract`, which is not `INextGenAdmins`.

After the deployment, it tries to call a function 
```solidity
function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {}
```
but triggers the `FunctionAdminRequired()` modifier, which checks for access to that function with `adminsContract` set:
```solidity
modifier FunctionAdminRequired(bytes4 _selector) {
    require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
    _;
}
```
Of course `FunctionAdminRequired` returns an error because it cannot call the `adminsContract` contract functions due to a non-existent address.


To run the test, change `/hardhat/scripts/fixturesDeployment.js` to a random address (_line 26_)
```diff
const hhCore = await nextGenCore.deploy(
    "Next Gen Core",
    "NEXTGEN",
-    await hhAdmin.getAddress(),
+    '0x1231233300000000000000000000000000000001'
)
```

Add this code to `/hardhat/nextGen.test.js` and run test (`npx hardhat test --grep "Change admin"`)

``
Minting nft with Index 0 is not allowed
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L108-L112


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
The constructor of the NextGenCore.sol contract includes an increment operation for the newCollectionIndex variable, ensuring that the newCollectionIndex start from 1. While adding or modifying additional data to the collection using setCollectionData() function _collectionID = 0 will not exist.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

    constructor(string memory name, string memory symbol, address _adminsContract) ERC721(name, symbol) {
        adminsContract = INextGenAdmins(_adminsContract);
        newCollectionIndex = newCollectionIndex + 1;
        _setDefaultRoyalty(0x1B1289E34Fe05019511d7b436a5138F361904df0, 690);
    }

Here In the constructor newCollectionIndex starts with 1.

## Tools Used
Manual

## Recommended Mitigation Steps
Increment should be removed so that Index starts with 0.


## Assessed type

Error