xanoutas/solidity-security-findings huggingface dataset:
Vote power can be manipulated to propose and/or pass needed proposals
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L564-L577
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L634-L657
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L1090-L1092
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L724-L738
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L672-L681


# Vulnerability details

## Impact

The PartyGovernance contract is susceptible to vote manipulation, as an attacker could potentially acquire a substantial loan, even without collateral, within a single block before submitting a proposal. The voting process solely considers this particular block for calculating voting power, creating a scenario where an attacker might execute arbitrary proposals with minimal associated risks.

## Proof of Concept
During proposal creation current timestamp is stored as creation date and previous second will be applicable during the acceptance. So it's possible to manipulate of vote power simply to take loan for that period.
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L564-L577
```
            ProposalStateValues({
                proposedTime: uint40(block.timestamp),
                passedTime: 0,
                executedTime: 0,
                completedTime: 0,
                votes: 0,
                totalVotingPower: _getSharedProposalStorage().governanceValues.totalVotingPower,
                numHosts: numHosts,
                numHostsAccepted: 0
            })
```
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L634-L657
```
uint96 votingPower = getVotingPowerAt(msg.sender, values.proposedTime - 1, snapIndex);
```

If the attacker will take a loan even without collateral, within that single block, they could manipulate the vote with minimal slippage, given the confined timeframe. In such a scenario, the attacker would gain the ability to execute any arbitrary code.

## Severity justification
While this vulnerability can be marked as not so important I need to insist that is more important for this contract that it possibly looks like.
With this vulnerability attacker can simply create his own proposal and insta accept it.

```
            ProposalStateValues({
                proposedTime: uint40(block.timestamp),
                passedTime: 0,
                executedTime: 0,
                completedTime: 0,
                votes: 0,
                totalVotingPower: _getSharedProposalStorage().governanceValues.totalVotingPower,
                numHosts: nu
No token whitelist leaves rageQuit() vulnerable to malicious ERC20 token contracts
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol#L344-L448
https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol#L388


# Vulnerability details

A malicious actor can exploit the ```PartyGovernanceNFT.sol::rageQuit()``` function by specifying a malicious IERC20 contract in the ```withdrawTokens``` array. 
The malicious contract could "donate" tokens to the proxy contract to pass the balance check [here](https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol#L388) and when the protocol attempts to transfer tokens from this contract, the malicious contract could execute arbitrary code to drain funds or another malicious activity.

## Impact
The ```PartyGovernanceNFT.sol``` is extemely open to attack vectors from lack of token whitelist.

## Tools Used
Manual Review
Foundry

## Recommended Mitigation Steps
Add a token whitelist at the initialization and a check in the rageQuit()








## Assessed type

Invalid Validation
Input validation for the fields within `opts` (like `opts.name`, `opts.symbol`, `opts.voteDuration`, etc.) is necessary to ensure they meet the expected criteria.
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350


# Vulnerability details

M3 - Input validation for the fields within `opts` (like `opts.name`, `opts.symbol`, `opts.voteDuration`, etc.) is necessary to ensure they meet the expected criteria.

    **poc**:
    ```solidity
    function _createParty() private returns (Party) {
        require(bytes(opts.name).length > 0, "Party name is required");
        require(bytes(opts.symbol).length > 0, "Party symbol is required");
        require(opts.governanceOpts.voteDuration > 0, "Vote duration must be greater than 0");
        // Additional validations as necessary
        
    }
    ```



## Assessed type

Other
In `batchRefund`, adding a check for sufficient balance before attempting refunds could prevent potential failures.
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350


# Vulnerability details

M2 - In `batchRefund`, adding a check for sufficient balance before attempting refunds could prevent potential failures.

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350

    **poc**:
    ```solidity
    function batchRefund() external returns () {
        require(address(this).balance >= totalRefundAmount, "Insufficient balance for refunds");
        
    }
    ```


## Assessed type

Other
The `batchRefund` function could benefit from access control checks, such as ensuring only authorized users can perform batch refunds.
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350


# Vulnerability details

M1 - The `batchRefund` function could benefit from access control checks, such as ensuring only authorized users can perform batch refunds.

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350

    **poc**:
    ```solidity
    function batchRefund() external onlyAuthorized returns () {
        
    }
    ```


## Assessed type

Access Control
Unbounded iteration over all index
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350


# Vulnerability details



## Impact
The transactions could fail if the array get too big and the transaction would consume more gas than the block limit. This will then result in a denial of service for the desired functionality and break core functionality.

## Proof of Concept
Functions like batchContribute() and batchRefund() loop over arrays of arbitrary length. If these arrays are too large, these functions could exceed the block gas limit, making them unable to be executed.


## Tools Used
Manual Review

## Recommended Mitigation Steps
Limit size of array to avoid gas shortage issue.



## Assessed type

DoS
Reentrancy on batchRefund making external call
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L350


# Vulnerability details

## Impact
Reentrancy can occur when the refund function being called inside the ```batchRefund``` function allows external contract calls that can trigger the ```batchRefund``` function again before the previous execution is completed.



## Proof of Concept
The batchRefund function is called with an array of tokenId. Inside the for loop, the refund function is called using ```this.refund``` which allows external contract calls.
```
    function batchRefund(
        uint256[] calldata tokenIds,
        bool revertOnFailure
    ) external returns (uint96[] memory amounts) {
        uint256 numRefunds = tokenIds.length;
        amounts = new uint96[](numRefunds);


        for (uint256 i; i < numRefunds; ++i) {
            (bool s, bytes memory r) = address(this).call(
                abi.encodeCall(this.refund, (tokenIds[i]))
            );


            if (!s) {
                if (revertOnFailure) {
                    r.rawRevert();
                }
            } else {
                amounts[i] = abi.decode(r, (uint96));
            }
        }
    }
```
If the external contract being called in the refund function has a fallback function that calls back into the batchRefund function, reentrancy can occur.
The external contract can call the batchRefund function again before the previous execution is completed, leading to recursive execution. This recursive execution can result in unexpected behavior and potentially exploit the contract's logic.


## Tools Used
Manual Review

## Recommended Mitigation Steps
To prevent reentrancy, ReentrancyGuard modifier ```nonReentrant``` by OpenZeppelin should be used to prevent multiple recursive calls within the same transaction.



## Assessed type

Reentrancy
wrong return value of totalVotingPower leads to break the `OffChainSignatureValidator#isValidSignature()` functionality
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/signature-validators/OffChainSignatureValidator.sol#L59-L60
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/signature-validators/OffChainSignatureValidator.sol#L67
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/signature-validators/OffChainSignatureValidator.sol#L73
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L390-L392


# Vulnerability details


## Bug Description

in the `OffChainSignatureValidator#isValidSignature()` function we returns the `singerVotingPowerBPS` in term of BPS(points) by mul it by 1000 and the totalVotingPower is returned by calling the `party.getGovernanceValues().totalVotingPower` which is normal value/number(not in BPS),however we have check that we require `singerVotingPowerBPS > totalVotingPower` which is impossible to happen because the singerVotingPowerBPS is smaller than  `totalVotingPower` which is in 1e18.

## Impact
The `OffChainSignatureValidator#isValidSignature()` have check that require `singerVotingPowerBPS > totalVotingPower` to return IERC1271.isValidSignature.selector, this check will never be passed as the singerVotingPowerBPS is in BPS value which way more smaller than `totalVotingPower` which is 1e18 decimals. 

## Proof of Concept
the `OffChainSignatureValidator#isValidSignature()` implemented as below

```solidity 
 function isValidSignature(
        bytes32 hash,
        bytes memory signature
    ) external view returns (bytes4) {
        uint8 v;
        bytes32 r;
        bytes32 s;
        assembly {
            // First word of signature after size contains r
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            // v is one byte which starts after s. type is uint8 so extra data will be ignored
            v := mload(add(signature, 0x41))
        }

        bytes memory message;
        assembly {
            // Raw message data begins after v. Overwriting part of s and v with size of `message`
            message := add(signature, 0x41)
            mstore(message, sub(mload(signature), 0x41))
        }

        // Recreate the message pre-hash from the raw data
        bytes memory encodedPacket = abi.encodePacked(
            "\x19Ethereum Signed Message:\n",
            Strings.toString(message.length),
            message
        );
        if (keccak256(encodedPacket) != hash) {
            revert MessageHashMismatch();
        }

        Party party = Party(payable(msg.sender));
        address signer = ecrecover(hash, v, r, s);
        //@audit we return vote power in BPS
        uint96 signerVotingPowerBps = party.getVotingPowerAt(
            signer,
            uint40(block.timestamp)
        ) * 10000;

        if (signerVotingPowerBps == 0
Send Ether will call instead of transfer
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L224


# Vulnerability details

## Impact
transfer() automatically forwards exactly 2300 gas to the receiving contract. This limitation can restrict smart contract's ability to interact with other contracts that require more gas for their operations like receiving eth, leading to failed transactions if the receiving contract's fallback function consumes more gas.

## Proof of Concept
**Fixed Gas Limit:** `transfer()` allocates a fixed gas amount of `2300` units, which is insufficient for contracts that require more gas to execute their transactions. This limitation constrains the smart contract's ability to interact with a range of external contracts, especially those requiring more complex computations.

**Transaction Failure Risk:** If a contract receiving Ether via `transfer()` has a payable fallback function that, directly or through a proxy, consumes more than `2300` gas units, the transaction will fail and revert. This behavior can lead to a cascade of issues, particularly in multi-contract operations or transactions.

Security Concerns: While transfer() was originally recommended to prevent reentrancy attacks, its rigid gas limit can inadvertently introduce other security vulnerabilities or logic flaws, especially when interfacing with more complex or evolving contract designs.



transfer() uses a fixed amount of gas, which can result in revert. https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/

## Tools Used
Manual Review

## Recommended Mitigation Steps
Replace the `transfer()` method with the `call` method for sending Ether. The call method offers greater flexibility by not imposing a fixed gas limit, enhancing compatibility with a variety of contracts and reducing the likelihood of transaction failures.


```solidity
(bool succeeded, ) = _to.call{value: _amount}(""); require(succeeded, "Transfer failed.");
require(succeeded, "failed"
```

**Note on Security:** When using call, it's crucial to implement proper security measures to prevent reentrancy attacks. This includes making all state changes before the external call and considering the use of reentrancy guard





## Assessed type

call/delegatecall
Potential negative value of votingPowerByTokenId
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol#L236


# Vulnerability details

## Impact
Based on the context and functionality being used in the `PartyGovernanceNFT` contract, an authority address can reduce voting power by specifying the degree of reduction but the negative difference wasn't considered.

## Proof of Concept
IN this function
```solidity
function decreaseVotingPower(uint256 tokenId, uint96 votingPower) external {
        _assertAuthority();
        mintedVotingPower -= votingPower;
        //@audit-check: no check to see if votingPower is less than  votingPowerByTokenId[tokenId]
        votingPowerByTokenId[tokenId] -= votingPower;

        _adjustVotingPower(ownerOf(tokenId), -votingPower.safeCastUint96ToInt192(), address(0));
    }
```
There was no check to see if the votingPower being more than the `votingPowerByTokenId[tokenId]` initial value leading to potential underflow and negative `votingPowerByTokenId[tokenId]`

## Tools Used
Manual Review
## Recommended Mitigation Steps
Add a check for seeing if votingPower inputted for reduction is more than allowed


## Assessed type

Under/Overflow
In some cases the crowdfund cant be finalized because the minContribution amount check is after the amount is reduced
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/ETHCrowdfundBase.sol#L256


# Vulnerability details

Because of a finding in the [previous contest](https://code4rena.com/reports/2023-04-party#m-03-contributions-can-be-smaller-than-mincontribution-and-may-receive-no-voting-power), the `minContribution` check is done after the amount is potentially reduced if refunding excess contribution. However this can be a problem if the `maxTotalContributions` - `minTotalContributions` is smaller than the `minContribution` and in some cases the crowdfund can be lost because of this.

Example:

```
minTotalContributions = 100 ether
maxTotalContributions = 102 ether
The current totalContributions = 99 ether
minContribution amount = 4 ether
```
When the last contributor wants to contribute he calls the function with 4 ether however the reduced amount will then be 3 ether and the tx will revert because of the `minContribution` check and the crowdfund will be lost. 

## Impact

There will be no way to finalize the crowdfund and because of that it will be lost even though it was supposed to be finalized. 

## Proof of Concept

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/ETHCrowdfundBase.sol#L240

```solidity
240:  amount -= refundAmount;
```

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/ETHCrowdfundBase.sol#L256

```solidity
256:  if (amount < minContribution_) {
257:      revert BelowMinimumContributionsError(amount, minContribution_);
258:  }
```

As you can see the amount is reduced and the check is done after it, the problem arises when the `maxTotalContributions` - `minTotalContributions` is smaller than the `minContribution` which will cause the crowdfund to be lost. 

## Tools Used

Manual Review

## Recommended Mitigation Steps

Because we cant move the check before the refund logic, the only way to prevent this is to check if the `minContribution` is bigger than the `maxTotalContributions` - `minTotalContributions` in the initialize function




## Assessed type

Other
Increasing or decreasing totalVotingPower or individualVotingPower will affect current distributions for users that have not yet claimed. 
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/distribution/TokenDistributor.sol#L259-L278


# Vulnerability details

## Impact
Altering the totalVotingPower or individualVotingPower will lead to unfair distributions among members that have not yet claimed

## Proof of Concept
A member of a party can call PartyGovernance#distribute which will transfer the specified amount to TokenDistributor contract, and the members of the party can claim a portion of "amount" based on the votingPower of party token they own. Each member can claim: `votingPower*amount/totalVotingPower`.

There are functions that allow party authorities to alter the totalVotingPower and votingPower of any member. However, altering any of these parameters when all members have not claimed their share of a distribution would be problematic.

Consider the following examples:
- aliceVotingPower=5, bobVotingPower=5, totalVotingPower=10
- Party starts a distribution of 100 USDC
- alice and bob should claim 50 USDC each.

Scenario A: totalVotingPower gets increased
- authority increases totalVotingPower to 15
- Alice claims 5*100/15=33 USDC
- Bob claims 5*100/15=33 USDC

Scenario B: totalVotingPower gets decreased
- authority decreases totalVotingPower to 7.5
- Alice claims 5*100/7.5=66 USDC
- Bob who has equal voting power as Alice claims 33 USDC

Scenario C: a member's votingPower gets altered
- authority increases alice's votingPower to 7.5
- Alice claims 7.5*100/10=75 USDC
- Bob, who should have claimed 50 USDC, claims 25 USDC because someone else's votingPower got increased

## Tools Used
Manual Review

## Recommended Mitigation Steps
Solution is to fetch and use the cached votingPower just before a distribution was made, just as is done for voting on a proposal.

Party should be able to add more funds to tokenDistributor


## Assessed type

Error
User loss his delegated voting power after delegation to another user.
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L368-L375


# Vulnerability details

## Vulnerability Details
When a user delegate voting power to another user, his previous voting power from delegation has been ignored at getVotingPowerAt since in case isDelegated is true getVotingPowerAt returns 0.

## Impact
Delegated voting power cannot be utilized when delegating to another user.

## Proof of Concept
1-User A possesses a total of 10 intrinsic voting power and 10 delegated voting power.
2-User A delegates their voting power to User B. As a result, User B now has 10 voting power, while User A's voting power becomes zero since the getVotingPowerAt function returns zero when isDelegated is true. The delegated amount becomes unusable for User A.

## Tools Used
Manual Review
## Recommended Mitigation Steps
In the getVotingPowerAt function, take into account the delegated voting power if isDelegate is true.


## Assessed type

Other
`decreaseVotingPower()` can be front-ran by an attacker to claim an amount of assets from the `TokenDistributor` more than he should be able to claim or withdraw more assets than he should be able to claim through `rageQuit()`
Audit: 2023-10-party-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L236


# Vulnerability details



### Overview of the vulnerability / PoC
---
The function [`decreaseVotingPower`](https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol) in `PartyGovernanceNFT` does not have a front-running protection against a user claiming his share of a distribution or a user ragequitting using a token which is going to get it's voting power decreased.

This allows a user to walk out of the protocol with more assets than he is supposed to

#### An example of the attack
1. A party member exists in a party which has a total voting power of `100e18` has a governance NFT token which has an id of `5`. This governance NFT token has a voting power of `10e18` meaning that the user owns 10% share of the party.

2. An authority decides to decrease the voting power of that token by 10% for some reason. So now the user shouldn't be able to walk away with more than 9% of the party's assets whether these assets exist in the party contract itself or the token distributor.

3. The member will front-run the `decreaseVotingPower` call with a call to `claim()` in `TokenDistributor` to claim his funds from the currently-available distributions (if he hasn't done that already). and walk out with his old share (10%) rather than 9%.

4. The member can also front-run the `decreaseVotingPower` call to rage quit from the party and withdraw his old share of assets (10%).


---
### Impact
---
A user can claim more assets than he should claim happen his voting power gets decreased by an authority for some reason.


---
### Remediation
---
A fix to the user being able to front-run `decreaseVotingPower` to claim assets from the token distributor is to create something like a timelock. A user requests withdrawal of assets from the token distributor, and only after X amount of time. He can claim those assets


## Assessed type

MEV