xanoutas/solidity-security-findings huggingface dataset:
Business Logic Vulnerability in dropTopVotedPiece Function
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L519


# Vulnerability details

Potential Risk:
The `dropTopVotedPiece` function in the `CultureIndex` contract allows the `dropperAdmin` to drop the top-voted piece. While the function checks if the caller is the `dropperAdmin`, there is a potential business logic vulnerability. The function only requires that the total vote weight of the top-voted piece meets or exceeds its `quorumVotes` to be dropped.

Proof of Concept (PoC):
Consider a scenario where an attacker gains control of the `dropperAdmin` account or convinces the `dropperAdmin` to perform a malicious action. The attacker could manipulate the voting system to inflate the total vote weight of a specific piece, making it meet the `quorumVotes` requirement even if it should not be dropped. This could lead to the unintended or premature dropping of art pieces.

Recommended Mitigation Steps:
To mitigate the business logic vulnerability in the `dropTopVotedPiece` function, you should consider implementing additional checks and safeguards to ensure that art pieces are dropped based on genuine and valid criteria. Here are some recommendations:

1. Review the criteria for dropping art pieces, such as `quorumVotes`, and ensure that it aligns with the intended logic and security requirements of your contract.

2. Consider adding a time-based requirement or cooldown period before a piece can be dropped. This can prevent premature drops and allow for more fair and secure voting.

3. Implement a multi-signature or multi-factor authentication mechanism for the `dropperAdmin` role to enhance security and prevent unauthorized drops.

4. Regularly monitor and audit the contract to detect any unusual voting patterns or anomalies that may indicate malicious activity.

5. Consider involving a third-party audit or security expert to review and assess the contract's functionality, especially in critical areas like voting and dropping pieces.

By implementing these mitigation steps, you can reduce the risk associated with the `dropTopVotedPiece` function and enhance the security and fairness of your contract. Additionally, it's crucial to keep the contract up-to-date with the latest security best practices and conduct thorough testing to identify and address potential vulnerabilities.



## Assessed type

Other
Input Validation for _vote Function
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L307


# Vulnerability details

Potential Risk:
The `_vote` function in the `CultureIndex` contract takes two parameters: `pieceId` and `voter`. While the function includes some input validation checks, there are some potential issues and missing checks that should be addressed.

Proof of Concept (PoC):
Consider a scenario where an attacker attempts to vote for a piece with an invalid `pieceId` or an invalid `voter` address:

// Attempt to vote with an invalid pieceId
_vote(MAX_PIECE_ID + 1, msg.sender);

// Attempt to vote with an invalid voter address
_vote(pieceId, address(0));

In these PoC examples, an attacker tries to vote with an out-of-range `pieceId` and an invalid voter address. The `_vote` function should have additional checks to prevent such scenarios.

Recommended Mitigation Steps:
To mitigate the risk of using invalid `pieceId` or `voter` addresses, consider adding or enhancing input validation checks within the `_vote` function. Here's a recommended solution:

function _vote(uint256 pieceId, address voter) internal {
    require(pieceId < _currentPieceId, "Invalid piece ID");
    require(voter != address(0), "Invalid voter address");
    require(!pieces[pieceId].isDropped, "Piece has already been dropped");
    require(votes[pieceId][voter].voterAddress == address(0), "Already voted"); // Updated this check
    require(_getPastVotes(voter, pieces[pieceId].creationBlock) > minVoteWeight, "Weight must be greater than minVoteWeight");

    uint256 weight = _getPastVotes(voter, pieces[pieceId].creationBlock);
    
    votes[pieceId][voter] = Vote(voter, weight);
    totalVoteWeights[pieceId] += weight;

    uint256 totalWeight = totalVoteWeights[pieceId];

    // TODO add security consideration here based on block created to prevent flash attacks on drops?
    maxHeap.updateValue(pieceId, totalWeight);
    emit VoteCast(pieceId, voter, weight, totalWeight);
}

In this solution:

- We've enhanced the input validation checks to ensure that the `voter` has not already voted for the same `pieceId` before allowing the vote.
- We've also combined the check for the minimum weight requirement into a single require statement for efficiency.
- These changes help prevent the use of invalid or unexpected input parameters and improve the overall input validation of the `_vote` function.

By implementing this solution, you can reduce the risk of issues related to invalid input parameters when voting for a piece.




## Assessed type

Invalid Validation
_verifyVoteSignature wrong implementation
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L431


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline));
here we are using nonces[from]++ for calculating voteHash but different from address can have the same 
nonces[from]++ ,therefore creating the same votehash.
## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

 function _verifyVoteSignature(
        address from,
        uint256[] calldata pieceIds,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal returns (bool success) {
        require(deadline >= block.timestamp, "Signature expired");

        bytes32 voteHash;

    @> voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline));

        bytes32 digest = _hashTypedDataV4(voteHash);a

        address recoveredAddress = ecrecover(digest, v, r, s);

        // Ensure to address is not 0
        if (from == address(0)) revert ADDRESS_ZERO();

        // Ensure signature is valid
        if (recoveredAddress == address(0) || recoveredAddress != from) revert INVALID_SIGNATURE();

        return true;
    }

## Tools Used
Manual Analysis
## Recommended Mitigation Steps


## Assessed type

Invalid Validation
Input Validation for createPiece Function
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L209


# Vulnerability details

Potential Risk:
The `createPiece` function in the `CultureIndex` contract takes two parameters: `metadata` and `creatorArray`. While the function calls the `validateCreatorsArray` and `validateMediaType` functions to validate the input data, it does not verify whether the provided `pieceId` is already used or whether it falls within a valid range. This could potentially lead to issues if the same `pieceId` is reused or if it exceeds the expected range.

Proof of Concept (PoC):
Consider a scenario where a malicious user attempts to reuse an existing `pieceId`:

// Existing piece with pieceId 1
ArtPieceMetadata memory existingMetadata;
CreatorBps[] memory existingCreators;

// Attempt to create a new piece with the same pieceId
createPiece(existingMetadata, existingCreators);

In this PoC, a malicious user attempts to create a new piece with the same `pieceId` as an existing one. The `createPiece` function does not have a check to prevent this, potentially leading to unexpected behavior.

Recommended Mitigation Steps:
To mitigate the risk of reusing existing `pieceId` values or exceeding valid ranges, consider adding a validation check for the `pieceId`. Here's a recommended solution:

function createPiece(
    ArtPieceMetadata calldata metadata,
    CreatorBps[] calldata creatorArray
) public returns (uint256) {
    uint256 creatorArrayLength = validateCreatorsArray(creatorArray);

    // Validate the media type and associated data
    validateMediaType(metadata);

    uint256 pieceId = _currentPieceId++;

    // Add a validation check for pieceId
    require(pieceId < MAX_PIECE_ID, "Invalid pieceId");

    // ... rest of the function ...

    emit PieceCreated(pieceId, msg.sender, metadata, newPiece.quorumVotes, newPiece.totalVotesSupply);

    // Emit an event for each creator
    for (uint i; i < creatorArrayLength; i++) {
        emit PieceCreatorAdded(pieceId, creatorArray[i].creator, msg.sender, creatorArray[i].bps);
    }

    return newPiece.pieceId;
}

In this solution:

- We've added a check to ensure that `pieceId` is within a valid range (less than `MAX_PIECE_ID`).
- This change helps prevent the reuse of existing `pieceId` values and ensures that the `pieceId` is within an expected range.

By implementing this solution, you can enhance the input validation of the `createPiece` function and reduce the risk of issues related to `pieceId` values.



## Assessed type

Invalid Validation
Signature Malleability in CultureIndex::_verifyVoteSignature function 
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L419-L444


# Vulnerability details

## Impact
The elliptic curve used in Ethereum for signatures is symmetrical, hence for every [v,r,s] there exists another [v,r,s] that returns the same valid result. Therefore [two valid signatures exist](https://www.youtube.com/watch?v=V3TJLDHZBFU) which allows attackers to compute a valid signature without knowing the signer's private key. `ecrecover()` is vulnerable to signature malleability [1](https://swcregistry.io/docs/SWC-117/) [2](https://swcregistry.io/docs/SWC-121/) so it can be dangerous to use it directly. 

An attacker can compute another corresponding [v,r,s] that will make this check pass due to the symmetrical nature of the elliptic curve. 
## Proof of Concept
``` javascript
        function _verifyVoteSignature(
        address from,
        uint256[] calldata pieceIds,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal returns (bool success) {
        require(deadline >= block.timestamp, "Signature expired");

        bytes32 voteHash;

        voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline));

        bytes32 digest = _hashTypedDataV4(voteHash);

        address recoveredAddress = ecrecover(digest, v, r, s);

        // Ensure to address is not 0
        if (from == address(0)) revert ADDRESS_ZERO();

        // Ensure signature is valid
        if (recoveredAddress == address(0) || recoveredAddress != from) revert INVALID_SIGNATURE();

        return true;
    }
```
## Tools Used

manual review

## Recommended Mitigation Steps
The easiest way to prevent this issue is to use OpenZeppelin’s [ECDSA.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/e70a0118ef10773457f670671baefad2c5ea610d/contracts/utils/cryptography/ECDSA.sol#L4) library and reading the comments above ECDSA's tryRecover() function provides very useful information on correctly implementing signature checks to prevent signature malleability vulnerabilities. More examples: [1](https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2023-04-11-cyfrin-hyperliquid-dex-report.pdf) [2](https://github.com/sherlock-audit/2022-09-harpie-judging/blob/main/010-M/1-report.md)

When using OpenZeppelin's ECDSA library, special care must be taken to [use version 4.7.3 or greater](https://github.com/sherlock-audit/2023-02-kairos-judging/issues/151), since previous versions contained a signature malleability bug.


## Assessed type

Other
Validate Creators Array
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L179


# Vulnerability details

Potential Risk:
The `validateCreatorsArray` function in the `CreatorUtils` contract performs input validation for the `creatorArray` parameter, which is an array of `CreatorBps` structs. While the function checks the individual elements of the array for valid addresses and ensures that the sum of `bps` values equals 10,000, it does not check for duplicate addresses in the array. This could lead to a situation where multiple creators have the same address, potentially causing unintended behavior.

Proof of Concept (PoC):
Consider a scenario where an attacker provides a 'creatorArray' with duplicate addresses:

CreatorBps[] memory maliciousCreators = new CreatorBps[](2);

// Duplicate address for two creators
maliciousCreators[0] = CreatorBps(address(creator1), 5000);
maliciousCreators[1] = CreatorBps(address(creator1), 5000);

// Attempt to validate the malicious creators array
validateCreatorsArray(maliciousCreators);

In this PoC, the attacker creates an array of 'CreatorBpswith' the same address for two creators. The 'validateCreatorsArray' function does not detect this as an issue, even though it should be considered invalid.

Recommended Mitigation Steps:
To improve the input validation for the creatorArray, you should consider adding validation checks to ensure that there are no duplicate addresses in the array. 

Here's a recommended solution:


function validateCreatorsArray(CreatorBps[] calldata creatorArray) internal pure returns (uint256) {
    uint256 creatorArrayLength = creatorArray.length;
    // Require that creatorArray is not more than MAX_NUM_CREATORS to prevent gas limit issues
    require(creatorArrayLength <= MAX_NUM_CREATORS, "Creator array must not be > MAX_NUM_CREATORS");

    uint256 totalBps;
    mapping(address => bool) addressSet; // Keep track of unique addresses

    for (uint256 i = 0; i < creatorArrayLength; i++) {
        require(creatorArray[i].creator != address(0), "Invalid creator address");
        require(!addressSet[creatorArray[i].creator], "Duplicate creator address");
        addressSet[creatorArray[i].creator] = true; // Mark the address as seen
        totalBps += creatorArray[i].bps;
    }

    require(totalBps == 10_000, "Total BPS must sum up to 10,000");

    return creatorArrayLength;
}

In this solution:

- We've added a 'mapping called 'addressSet' to keep track of unique addresses encountered in the 'creatorArray'.
- Before processing each element, we check if the address has been seen before (indicating a duplicate) and revert the transaction if a duplicate is detected.
- This change ensures that the 'creatorArray' does not contain duplicate addresses, enhancing the security of the input validation.

By implementing this solution, you can prevent the use of duplicate addresses in the 'creatorArray' and i
Missing Input Validation for Media Type
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L159


# Vulnerability details

The `validateMediaType` function in the `ArtPieceMetadata` contract performs some input validation for the `mediaType` field in the `metadata` parameter. However, it lacks validation for the associated data fields based on the `mediaType`. This could lead to issues where the `metadata` object is considered valid even when required data fields for certain media types are missing or empty.

Consider a scenario where an attacker creates an ArtPieceMetadata` object with an invalid mediaType and missing data for that media type:


ArtPieceMetadata memory maliciousMetadata = ArtPieceMetadata(
    MediaType(6), // Invalid media type
    "",           // Empty image URL
    "Title"
);

validateMediaType(maliciousMetadata);

In this PoC, the attacker sets an invalid `mediaType` (6) and provides an empty image URL. The `validateMediaType` function would not detect this as an issue, even though it should be considered invalid.

Recommended Mitigation Steps:
To improve the input validation for the `metadata` object, you should consider adding validation checks for the associated data fields based on the `mediaType`. Here's a recommended solution:

function validateMediaType(ArtPieceMetadata calldata metadata) internal pure {
    require(uint8(metadata.mediaType) > 0 && uint8(metadata.mediaType) <= 5, "Invalid media type");

    if (metadata.mediaType == MediaType.IMAGE)
        require(bytes(metadata.image).length > 0, "Image URL must be provided");
    else if (metadata.mediaType == MediaType.ANIMATION)
        require(bytes(metadata.animationUrl).length > 0, "Animation URL must be provided");
    else if (metadata.mediaType == MediaType.TEXT)
        require(bytes(metadata.text).length > 0, "Text must be provided");
    else
        revert("Invalid media type"); // Add this to handle unknown media types
}


In this solution:

- We've added an additional `else` branch to handle unknown `mediaType` values and revert the transaction to prevent processing invalid data.
- This change ensures that the `metadata` object is properly validated based on the `mediaType`, preventing invalid or incomplete data from being considered as valid.

By implementing this solution, you can enhance the security and reliability of your input validation in the `validateMediaType` function.




## Assessed type

Invalid Validation
wrong implementation of  maxHeap.extractMax();
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L529


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
wrong implementation of  maxHeap.extractMax(); as it should return values but here its not assigned to anything.
## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

 maxHeap.extractMax();

in Maxheap.sol we have define :
function extractMax() external onlyAdmin returns (uint256, uint256) {
        require(size > 0, "Heap is empty");

        uint256 popped = heap[0];
        heap[0] = heap[--size];
        maxHeapify(0);

        return (popped, valueMapping[popped]);
    }

so it should be some return value.
## Tools Used
Manual Analysis
## Recommended Mitigation Steps

(uint256, uint256)=maxHeap.extractMax();


## Assessed type

Context
Reverting when the heap is full
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/MaxHeap.sol#L119


# Vulnerability details

Reverting when the heap is full: 
    a) You mentioned in the comments that the function will revert if the heap is full. 
    b) However, the code as it stands doesn't have any logic to check if the heap is indeed full. 
    c) Depending on the context, you might want to add a check to ensure that the heap doesn't exceed a certain maximum size.

---------
SOLUTION:
---------

uint256 public maxHeapSize;  // Define the maximum heap size as a state variable

constructor(uint256 _maxHeapSize) {
    maxHeapSize = _maxHeapSize;
}

function insert(uint256 itemId, uint256 value) public onlyAdmin {
    require(size < maxHeapSize, "Heap is full, cannot insert more items");  // Check if the heap is full

    heap[size] = itemId;
    valueMapping[itemId] = value; // Update the value mapping
    positionMapping[itemId] = size; // Update the position mapping

    uint256 current = size;
    while (current != 0 && valueMapping[heap[current]] > valueMapping[heap[parent(current)]]) {
        swap(current, parent(current));
        current = parent(current);
    }
    size++;
}



## Assessed type

Invalid Validation
Efficiency
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/MaxHeap.sol#L120


# Vulnerability details

Depending on the size of your heap, the while loop may execute a significant number of times. 
Consider whether you can optimize this loop for performance, especially if you expect a large number of insertions.



## Assessed type

Loop
Use SafeMath for overflow protection
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/NontransferableERC20Votes.sol#L134


# Vulnerability details

Unchecked math could potentially trigger overflows.

Recommendation: Utilize SafeMath library for overflow safe operations.

```
using SafeMath for uint256;

function mint(address account, uint256 amount) public onlyOwner {

  // Overflow protected
  totalSupply = totalSupply.add(amount);

  // Internal logic
}
```



## Assessed type

Under/Overflow
Slippage protection missing
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/MaxHeap.sol#L136


# Vulnerability details

The MaxHeap contract does not check for slippage when updating item values. This could enable the admin to manipulate asset prices.

**Recommendation:** Implement slippage protection by adding min/max checks in updateValue():

```diff
function updateValue(uint256 itemId, uint256 newValue) public onlyAdmin {
+   uint256 oldValue = valueMapping[itemId];
+   uint256 minValue = oldValue - (oldValue * 10 / 100); // 10% slippage allowed  
+   uint256 maxValue = oldValue + (oldValue * 10 / 100);

+   require(newValue >= minValue && newValue <= maxValue, "Slippage limit exceeded");

   // Update value mapping
   valueMapping[itemId] = newValue;

   // Maintain max heap property
   // ...
```



## Assessed type

Invalid Validation
Loss of precision in calculations
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/MaxHeap.sol#L80


# Vulnerability details

The use of regular division can lead to loss of precision. This could enable certain manipulations through precision attacks.

Recommendation: Use SafeMath's div for integer division.

Division used in `parent()` can lead to loss of precision. Safemath usage is suggested:

```diff  
- return (pos - 1) / 2; 
+ return (pos - 1).div(2);
```



## Assessed type

Math
Tighten Admin Access Control
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L519


# Vulnerability details

Admin functions do not use a custom admin role and rely only on owner access control.

Recommendation: Implement a custom admin role.


```solidity 
// Custom admin role instead of owner
enum Role {
    ADMIN
}

// Restrict drop function
function dropTopVotedPiece() external onlyRole(Role.ADMIN) {
   // Logic 
}
```



## Assessed type

Access Control