xanoutas/solidity-security-findings huggingface dataset:
propose function Can lead to unexpected behavior 
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/script/ProposeDAOV3UpgradeMainnet.s.sol#L54


# Vulnerability details

## Impact
Problème in the propose function, specifically in the construction of the targets, values, signatures, and calldatas arrays. These arrays are used to define the transactions that will be executed within the proposal, So the problem  arises from the use of a fixed-size array (numTxs) to store the transactions, an attacker can manipulate the value of numTxs, ta f would  be able to exceed the array bounds and execute additional unintended transactions within the proposal.

## Proof of Concept

In the propose function , we have a fixed-size array called targets, which holds the addresses of the contract targets for the proposal. The size of this array is determined by the numTxs variable the problem arises from the fact that the numTxs value is passed as an input parameter to the function, which means it can be manipulated by an attacker. If an attacker can set numTxs to a value greater than the predefined size of the targets array, they can exceed the array bounds and add additional transactions to the proposal
As an example : 

function maliciousPropose() public {
    uint8 numTxs = 11; // Set numTxs to a value greater than the predefined size

    address[] memory targets = new address[](numTxs);
    uint256[] memory values = new uint256[](numTxs);
    string[] memory signatures = new string[](numTxs);
    bytes[] memory calldatas = new bytes[](numTxs);

    // Populate the arrays with transactions
    for (uint8 i = 0; i < numTxs; i++) {
        // Set the transaction details as desired
        targets[i] = <address>;
        values[i] = <value>;
        signatures[i] = <signature>;
        calldatas[i] = <calldata>;
    }

    // Perform the proposal
    proposalId = propose(
        NOUNS_DAO_PROXY_MAINNET,
        daoV3Implementation,
        timelockV2,
        ETH_TO_SEND_TO_NEW_TIMELOCK,
        erc20Transferer,
        forkEscrow,
        forkDeployer,
        erc20TokensToIncludeInFork,
        description
    );
}

- the code show that the attacker sets numTxs to a value of 11, which exceeds the predefined size of the targets array. This allows the attacker to add an additional transaction to the proposal, potentially leading to unintended behavior.
The result of the code is the maliciousPropose function attempts to create an array of size 11 for the targets array, even though the contract expects a maximum of 10 transactions (numTxs = 10). This exceeds the predefined size and can lead to unexpected behavior or errors during execution.

## Tools Used
Manuel review 
## Recommended Mitigation Steps
 use a dynamic data structure such as a dynamic array or a mapping to store the transactions. This will prevent potential buffer overflow vulnerabilities and allow for more flexibility in handling transactions within the proposal.


## A
Incorrect checking for address(0) in `delegate`
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol#L124


# Vulnerability details

## Impact

According to `delegate` NatSpec: 

```
    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
```

`delegatee` parametr is the address to delegate votes to.

However, whenever this address is being set to 0, the `delegatee` paramater is being set to `msg.sender` instead of revert.
This behaviour may lead to confusion, especially that this function is `public`, thus can be called by anyone.

## Proof of Concept

```
File: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol

123: function delegate(address delegatee) public {
124:        if (delegatee == address(0)) delegatee = msg.sender;
125:        return _delegate(msg.sender, delegatee);
126:    }

```

The `delegatee` is incorrectly set to `msg.sender`, while it should revert for address(0). This may lead to some unexcepted behaviour.


## Tools Used

Manual code review

## Recommended Mitigation Steps

Revert when `delegatee == address(0)`





## Assessed type

Other
A Storage Write Removal Bug in NounsDAOProxy.sol
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol#L108-L124


# Vulnerability details

## Summary
In _fallback(), Calling functions that conditionally terminate the external EVM call using the assembly statements ``return(...)`` may result in incorrect removals of prior storage writes.

## Impact

In NounsDAOProxy.sol, _fallback() is given as below. The contract is affected by the bug called **Storage Write Removal Bug** which was introduced in solidity version 0.8.13 and it has been fixed on Solidity version 0.8.17. 

```Solidity
File: nouns-contracts/contracts/governance/NounsDAOProxy.sol

108    function _fallback() internal {
109        // delegate all other functions to current implementation
110        (bool success, ) = implementation.delegatecall(msg.data);
111
112        assembly {
113            let free_mem_ptr := mload(0x40)
114            returndatacopy(free_mem_ptr, 0, returndatasize())
115
116            switch success
117            case 0 {
118                revert(free_mem_ptr, returndatasize())
119            }
120            default {
121                return(free_mem_ptr, returndatasize())
122            }
123        }
124    }
```

At L-121, the _fallback() has used the inbuilt inline assembly return(...) in an inline assembly block which is the prerrequiste of this bug. Such an inline assembly call will not return from the current function, but instead result in an early successful (i.e. non-reverting) termination of the entire external EVM call.

**Further bug description:**
A call to a Yul function that conditionally terminates the external EVM call could result in prior storage writes being incorrectly removed by the Yul optimizer. This used to happen in cases in which it would have been valid to remove the store, if the Yul function in question never actually terminated the external call, and the control flow always returned back to the caller instead. Conditional termination within the same Yul block instead of within a called function was not affected. In Solidity with optimized via-IR code generation, any storage write before a function conditionally calling ``return(...)`` or ``stop()`` in inline assembly, may have been incorrectly removed, whenever it would have been valid to remove the write without the ``return(...)`` or ``stop()``. In optimized legacy code generation, only inline assembly that did not refer to any Solidity variables and that involved conditionally-terminating user-defined assembly functions could be affected.

Solidity official reference: 
https://soliditylang.org/blog/2022/09/08/storage-write-removal-before-conditional-termination/

**Solidity has officially considered this bug as Medium/High severity finding which later fixed in version 0.8.17.**

## Proof of Concept
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-cont
Unauthorized Cancellation of Proposals.
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L387-L389


# Vulnerability details

## Impact
An attacker who gains control of a proposer's account can cancel legitimate proposals, leading to the disruption of the governance process.

## Proof of Concept
[NounsDAOLogicV3.sol#L387-L389](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L387-L389)

```solidity
    function cancel(uint256 proposalId) external {
        ds.cancel(proposalId);
    }
```

`cancel()`:
   - Attack Surface: The ability to cancel a proposal.
   - Potential Attack Vectors:
     - Unauthorized cancellation of a proposal by an attacker who gains control of a proposer's account.
     - Cancelling a legitimate proposal to disrupt the governance process.


The `cancel()` function is being called on an instance of the `NounsDAOStorageV2` contract (represented by `ds`). The `cancel()` function of the `NounsDAOStorageV2` contract would contain the actual implementation for cancelling a proposal.

Scenario:
1. An attacker gains control of a proposer's account, either by compromising their private key or by exploiting a vulnerability in the proposer's system.
2. The attacker identifies a legitimate proposal that is in progress and has not been executed yet.
3. The attacker calls the `cancel()` function, providing the proposal ID of the targeted proposal.
4. Since the `cancel()` function lacks proper authorization checks, it allows the attacker to cancel the proposal, even though they are not the original proposer or a signer of the proposal.
5. As a result, the legitimate proposal is cancelled, disrupting the governance process and potentially causing financial losses or other adverse effects.

The absence of proper authorization checks in the `cancel()` function allows an attacker to exploit the vulnerability and cancel proposals without the necessary permissions. This can lead to the manipulation or disruption of the governance process, undermining the integrity of the smart contract system.

References:
- Solidity Documentation: Access Control Best Practices (https://docs.soliditylang.org/en/v0.8.9/security-considerations.html#access-control)
- OpenZeppelin: Role-Based Access Control (https://docs.openzeppelin.com/contracts/3.x/access-control)

## Tools Used
Manual Review

## Recommended Mitigation Steps
Only the proposer or authorized signers should be able to cancel a proposal. This can be achieved by adding checks to verify the sender's authority before allowing the cancellation.


## Assessed type

Governance
Unauthorized Proposal Updates and Execution.
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L338-L354
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L313-L322
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L348-L354


# Vulnerability details

## Impact
An attacker with access to the proposer's account can modify proposal data, including the description and transactions. This allows them to execute unauthorized actions, potentially leading to financial losses, contract manipulation, or disruption of the DAO's operations. The unauthorized changes can also undermine the trust and integrity of the governance process.

## Proof of Concept
[`updateProposalBySigs(), updateProposalDescription(),`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L338-L354) and [`updateProposalTransactions()`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L313-L322) lack proper access control checks, this means that any address can call these functions and update the proposal data, regardless of whether they are the authorized proposer or not. Additionally, the `updateProposalBySigs()` function requires the original signers to sign the update, but there is no validation or verification of the signatures, allowing an attacker to manipulate the signatures.

But the most the vulnerable line where the [updateProposalBySigs](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol#L348-L354) function is called is.
```solidity
ds.updateProposalBySigs(
    proposalId,
    proposerSignatures,
    NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas),
    description,
    updateMessage
);
```
This line calls the `updateProposalBySigs` function from the `ds` contract and passes the `proposalId`, `proposerSignatures`, `targets`, `values`, `signatures`, `calldatas`, `description,` and `updateMessage` as arguments.

the `updateProposalBySigs()` function. This vulnerability is related to the manipulation of the proposal data and signatures, allowing unauthorized actions to be executed.

Breakdown.

1. The `updateProposalBySigs()` function allows the proposer to update a proposal's transactions and description.
2. The function requires the original signers to sign the update.
3. The function accepts various parameters, including `proposerSignatures`, which is an array of signers who have signed the proposal and their signatures.

The vulnerability arises if there is inade
Some expired proposals on v1 may be wrongly marked as Queued, and will be executable.
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L662


# Vulnerability details

## Impact
Proposals that should have Expired(based on timelockv1 GRACE_PERIOD) will be wrongly marked as `Queued` and will be executable.

## Proof of Concept
The [`stateInternal`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L662) function checks if:
```solidity
function stateInternal(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId)
    internal
    view
    returns (NounsDAOStorageV3.ProposalState)
{
    ...
    else if (block.timestamp >= proposal.eta + getProposalTimelock(ds, proposal).GRACE_PERIOD()) {
        return NounsDAOStorageV3.ProposalState.Expired;
    } else {
        return NounsDAOStorageV3.ProposalState.Queued;
    }
    ...
}
```
For proposals made before the upgrade, there is no `executeOnTimelockV1` flag. So [`getProposalTimelock`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L520) function will return (timelockV2 contract) because it assumes that `executeOnTimelockV1` flag was set to false.

For those proposals, `if (block.timestamp >= proposal.eta + getProposalTimelock(ds, proposal).GRACE_PERIOD())` check will not be accurate because it will use the `GRACE_PERIOD` of timelockV2(21 days), when it should use timelockV1's `GRACE_PERIOD`(14 days).

So for about 7 days, those proposals will be `Queued`, when they should be `Expired`, so those `Expired` proposals will be executable for that period.

## Tools Used
Manual Review
## Recommended Mitigation Steps
- Proposals after the upgrade should have `executeOnTimelockV2` flag instead of `executeOnTimelockV1` flag.
    - `executeOnTimelockV1` function should be modified to set the newProposal's `executeOnTimelockV2` flag to false
    - getProposalTimelock should be modified to return timelockv2 contract only if `executeOnTimelockV2` flag was set to true



## Assessed type

Error
Proposers and signers can vote directly on their proposals or indirectly by sending their nouns to other address at creation block to vote
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol#L222
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol#L326


# Vulnerability details

## Impact
Probability of winning a proposal is not 50%(as it should be), but ((0.5*totalSupply) + max(proposalThreshold,proposerNounsBalance))/totalSupply 

## Proof of Concept
Before a Proposer creates a proposal, his voting power must have reached a proposal threshold. This proposal threshold is set by admin, and is between 1/1000 and 1/10 of the adjustedTotalSupply of Noun tokens.

After a proposal has been created, other token holders can vote for or against the proposal during the voting period. And if for votes>against votes, then proposal will succeed, else defeated.

The problem here is that Proposers are allowed to vote on their proposals, so each proposal has a greater chance of going in favour of the proposer. Recall also that to create a proposal, proposer must have propThreshold votes. So, in general, each proposal would start with >=propThreshold for votes whenever a proposer votes for his proposal.

This means that the probability of winning a proposal is not 50%(as it should be), but instead, ((0.5*totalSupply) + max(proposalThreshold,proposerNounsBalance))/totalSupply (which is >50%). So the higher the proposalThreshold, the easier it is to win a proposal.

Proposer can alternatively send his nouns to another address just at proposal creationBlock so as to use that address to vote on his proposal. Then, he would send the tokens back to Proposer to avoid proposal cancellation.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Don't allow proposers to vote on their proposals, and when voting, use the nouns balance of an address at `creationBlock-1`, instead of at [`creationBlock`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol#L326) 


## Assessed type

Invalid Validation
no way to disable update period of proposal, could cause unnecessary delay and longer proposal lifecycle
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L891-L915


# Vulnerability details

## Impact
newly introduced update period in V3 version allow user to update their proposal before their voting can start. However, protocol not allow user to disable or skip this period, this can cause unnecessary longer proposal lifecyle when user don't want to make any update to his proposal.

## Proof of Concept

Current implementation of creating new proposal forced proposal to always enter update period before it can enter start period (which itself have voting delay) : 

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L898-L900

```solidity
    function createNewProposal(
        NounsDAOStorageV3.StorageV3 storage ds,
        uint256 proposalId,
        uint256 proposalThreshold_,
        uint256 adjustedTotalSupply,
        ProposalTxs memory txs
    ) internal returns (NounsDAOStorageV3.Proposal storage newProposal) {
        // @audit - updatePeriod is forced and not an option
        uint64 updatePeriodEndBlock = SafeCast.toUint64(block.number + ds.proposalUpdatablePeriodInBlocks);
        // @audit - besides update period, start block itself have voting delay
        uint256 startBlock = updatePeriodEndBlock + ds.votingDelay;
        uint256 endBlock = startBlock + ds.votingPeriod;

        ....
    }
```

This design is problematic and can cause longer proposal lifecycle when it is not desired.

Updatable period can be up to 7 days (based on max config), and voting delay can be up to 14 days. (based on max config).

If for instance, the proposal creator is sure about his proposal and will not make any update, his proposal will take up to 14 + 7 = 21 days before the voting can start, this will make proposal lifecycle will take longer when it doesn't have to and not good for user experience. 

The extra un-avoided delay (up to 7 days) is unacceptable from user experience perspective and I believe this is medium severity.

## Tools Used

Manual review

## Recommended Mitigation Steps

Consider to add functionality to disable update period when user create proposal and also inside update proposal when user sure about his update and want to end update period. 

In front-end side, make sure user aware of this updatable period functionality and provide tick button for instance, to enable this period.











## Assessed type

Timing
Proposals will be executed against intention of proposer at unfavourable periods.
Audit: 2023-07-nounsdao-findings
Severity: MEDIUM

# Lines of code

https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L438-L458
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L479-L483
https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L490-L493


# Vulnerability details

## Impact
There could be some proposals which the proposer may want to queue and execute at a specific period.
In such scenarios, a random user could `queue` or `execute` such proposals against the intention of the proposer.

## Proof of Concept
The [`queue`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L438) and [`execute`](https://github.com/nounsDAO/nouns-monorepo/blob/718211e063d511eeda1084710f6a682955e80dcb/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol#L479) functions are callable by anyone. So when a proposal succeeds, anyone can `queue` that proposal id, and when eta is reached, anyone can `execute` the proposal.

And the ProposatTxs does not have a "time of execution" field:
```solidity
struct ProposalTxs {
    address[] targets;
    uint256[] values;
    string[] signatures;
    bytes[] calldatas;
}
```

Consider the following scenarios:

- A proposer creates a proposal on December 1st to donate to charity on january 1st. A random user can queue and execute that proposal before january 1st against the intention of the proposer.
- A proposer has made some market analysis, and creates a proposal to invest funds in an external De-Fi yield strategy at a time when he knows it would be favourable. A random user can execute such proposal before then, when it is not favourable, which could lead to fund loss.
- A proposer makes a proposal to airdrop tokens, to celebrate Protocol's anniversary. A random user can execute such proposal before the anniversary date.

Random users should not be allowed to execute any proposal at anytime because time of execution also plays an important role in determining a successful proposal.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider implementing one of these:
- The ProposalTxs should also contain a "time of execution" field, which should prevent anyone from executing the proposal before the expected date set by proposer. If "time of execution" is 0, then anyone can `queue` and `execute` the proposal at anytime
- Restrict `queue` and `execute` function to be callable only by proposer. This should be implemented in `queueOrRevertInternal` or `executeInternal` functions.


## Assessed type

Access Control