xanoutas/solidity-security-findings huggingface dataset:
Hash Collisions and Front-Running Risk
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/ed47c841a19abd26681110a26ef03c446da2b6dd/contracts/ERC20MultiDelegate.sol#L186
https://github.com/code-423n4/2023-10-ens/blob/ed47c841a19abd26681110a26ef03c446da2b6dd/contracts/ERC20MultiDelegate.sol#L15-L20


# Vulnerability details

https://github.com/code-423n4/2023-10-ens/blob/ed47c841a19abd26681110a26ef03c446da2b6dd/contracts/ERC20MultiDelegate.sol#L186
https://github.com/code-423n4/2023-10-ens/blob/ed47c841a19abd26681110a26ef03c446da2b6dd/contracts/ERC20MultiDelegate.sol#L15-L20

- Salt Value in Proxy Deployment: The contract uses a salt value of 0 during the deployment of proxy delegator contracts. This introduces a significant security concern related to potential hash collisions. If multiple delegators attempt to deploy to the same address simultaneously, only one of these transactions will succeed, and the others will revert due to the creation of a contract with the same address. This creates the risk of a race condition where transactions may compete, resulting in unintended reverts. Confirmed this is possible due to usage of only salt and delegatee address as the uniqueness parameters. The salt value is constant, and if delegators/attacker delegates to same delegatee, then same proxy address will be created/used.

- Potential Front-Running Risk: In addition to hash collisions, there's a potential front-running risk. An attacker may exploit this by guessing the salt value and front-running a deployment transaction to become the `msg.sender`. This could enable the attacker to approve themselves for unlimited tokens. Have not confirmed that this is actually possible.

Recommendations:

1. Unique and Randomized Salt Value: To mitigate hash collision risks, it's advisable to use a unique and randomized salt value for each proxy contract deployment. This would help prevent multiple delegators from inadvertently reverting their transactions due to address conflicts.

2. Access Control for Proxy Deployment: Implement access control mechanisms to ensure that only authorized contracts, such as the ERC20MultiDelegate contract, can deploy proxy delegators. This can help prevent unauthorized contracts from interfering with proxy deployments.

---

Two or More Delegators Sharing a Delegator Proxy:

- Proxy Contract Creation: The current contract design may inadvertently allow two or more delegators to share the same delegator proxy contract when they delegate to the same delegatee. This is not the intended functionality, as each delegator should have a separate delegator proxy for each delegatee they are delegating to.

- Access Control: While some level of access control seems to exist, it's essential to verify that unauthorized users cannot create or access delegator proxy contracts.

Recommendations:

1. Enforce Unique Proxy Contracts: Ensure that each delegator has a unique proxy contract for each delegatee they delegate to. This prevents multiple delegators from sharing the same
people can steal others voting power by creating mlicous proxy contracts 
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L198


# Vulnerability details

## Impact
bad actor can control over the other peoples voting power in delegate proxy contracts. 

lets start from `delegateMulti` when somebody calls it it leads to `_delegateMulti` and it calls `_processDelegation(source, target, amount);` in the process of loop.

if you look at this function

```solidity 
function _processDelegation(
        address source,
        address target,
        uint256 amount
    ) internal {
        uint256 balance = getBalanceForDelegate(source);

        assert(amount <= balance);

        deployProxyDelegatorIfNeeded(target);
        transferBetweenDelegators(source, target, amount);

        emit DelegationProcessed(source, target, amount);
    }

```
it gonna deploy to if needed as the `deployProxyDelegatorIfNeeded` works that way 

now lets look at the function `deployProxyDelegatorIfNeeded`

```solidity 

    function deployProxyDelegatorIfNeeded(
        address delegate
    ) internal returns (address) {
        address proxyAddress = retrieveProxyContractAddress(token, delegate);

        // check if the proxy contract has already been deployed
        uint bytecodeSize;
        assembly {
            bytecodeSize := extcodesize(proxyAddress)
        }

        // if the proxy contract has not been deployed, deploy it
        if (bytecodeSize == 0) {
            new ERC20ProxyDelegator{salt: 0}(token, delegate);
            emit ProxyDeployed(delegate, proxyAddress);
        }
        return proxyAddress;
    }
```

it checks if the proxy address exists already. if yes it will skip 
if not it generates address 
BUT if we look at how it generates

in `retrieveProxyContractAddress`

```solidity 
 function retrieveProxyContractAddress(
        ERC20Votes _token,
        address _delegate
    ) private view returns (address) {
        bytes memory bytecode = abi.encodePacked(
            type(ERC20ProxyDelegator).creationCode, 
            abi.encode(_token, _delegate)
        );
        bytes32 hash = keccak256(
            abi.encodePacked(
                bytes1(0xff),
                address(this),
                uint256(0), // salt
                keccak256(bytecode)
            )
        );
        return address(uint160(uint256(hash)));
    }


```
You can see there is no increasing NOUNCE in the hashing process which is allowing bad actore create address with frontrunning user and creating exat same hash and deploying it as proxy delegate and having control over it and when the user comes to this step `deployProxyDelegatorIfNeeded` will skip because it already deployed and bad actore has control over it
## Proof of Concept
```solidity 

    function retrieveProxyContractAddress(
        ERC20Votes _token,
        address _delegate
    ) private view returns (address) {
        bytes memory bytecode = abi.encodePacked(
            typ
ERC20ProxyDelegator contract will always lead to zero approval
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L17


# Vulnerability details


## Impact
In constructor of ERC20ProxyDelegator contract ``` _token.approve``` have type(uint256).max. This leads to approval remain zero as nothing will happens due to wrong value provided.

The main reason is due to the max approval attainable is type(uint256).max – 1.

This error makes functionality of the whole ```ERC20MultiDelegate``` contract useless as the resulting approval will always be zero.

## Proof of Concept
The bug exists in  ```ERC20ProxyDelegator``` where _token.approve have type(uint256).max value.

```
contract ERC20ProxyDelegator {
    constructor(ERC20Votes _token, address _delegate) {
        _token.approve(msg.sender, type(uint256).max);
        _token.delegate(_delegate);
    }
}
```

## Tools Used
Manual code Review

## Recommended Mitigation Steps
Use correct syntax of ```type(uint256).max – 1``` for approve instead of type(uint256).max for ERC20ProxyDelegator contract.

```
contract ERC20ProxyDelegator {
    constructor(ERC20Votes _token, address _delegate) {
-        _token.approve(msg.sender, type(uint256).max);
+       _token.approve(msg.sender, (type(uint256).max -1));
        _token.delegate(_delegate);
    }
}
```







## Assessed type

Math
"deployProxyDelegatorIfNeeded" Can Be Exploited To Steal Funds Or Even Cause Denial Of Service
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L186
https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L173-L190


# Vulnerability details

## Impact
In circumstances whereby transferIndex is greater than or equal to sources length but less than targets length, there are remaining target addresses to process. DelegateMulti Function calls createProxyDelegatorAndTransfer to handle any remaining target amounts after the transfer process. In this process a new proxy delegator is deployed for the remaining targets (if needed) in which the address is retrieved and ERC20 tokens are transferred from the msg.sender to the address. However, during the deployment of the new proxy contract, it takes in salt: 0 (Technically gives salt a fixed value), which ultimately allows front running of the deployment to that address (by using the salt), steal the funds or even DOS the deployment.

## Proof of Concept
The function deployProxyDelegatorIfNeeded takes in "new ERC20ProxyDelegator{salt: 0}(token, delegate);" which deploys a proxy delegator if needed to facilitate "token.transferFrom(msg.sender, proxyAddress, amount);" in the function createProxyDelegatorAndTransfer. However, it assumes salt as a fixed value 0 required to invoke CREATE2, which is wrong as assuming salt as a fixed value renders CREATE2 of no use as the deployment can be front-runned for deployment to that address and then the original deployment will almost always revert.

Consider this scenario:
1. Alice invokes "function DelegateMulti" with more targets address than sources addressed. This technically makes it possible for the function to call "createProxyDelegatorAndTransfer" to handle any remaining target amounts after the transfer process.
2. In the process, "createProxyDelegatorAndTransfer" calls "deployProxyDelegatorIfNeeded", which technically deploys a proxy delegator for the target (if it has not been deployed yet).
3. Bob (attacker) already saw the opportunity and looms in to front run the deployment for that proxy address. Bob successfully front-run the deployment by using salt (fixed at 0) 

That ultimately means that the original deployment will always revert, and Bob is liable to receive the vote tokens facilitated to the proxyaddress in the function createProxyDelegatorAndTransfer (*token.transferFrom(msg.sender, proxyAddress, amount*) after the "retrieveProxyContractAddress". Bob successfully DOS the deployment and also stole the ERC20 vote tokens.


See Recommended Mitigation.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Salt should not be a fixed value that can easily be passed. And also consider calling CREATE2 from within the contract. See live example of CREATE2 in development/production (where whenever a user creates a new liquidity pair, CREATE2 is used to deploy a new pair contract with salt pick
`ERC20Votes` tokens has maximum token supply capped at `type(uint208).max` approving `type(uint256).max` in `ERC20ProxyDelegator` will cause overflow
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L17


# Vulnerability details

## Impact
Maximum token supply in OpenZeppelin `ERC20Votes.sol`. Defaults to `type(uint208).max` (2^208^ - 1).
This maximum is enforced in `{_update}`. It limits the total supply of the token, which is otherwise a uint256,
     * so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not remove the underlying limitation, and will cause `{_update}` to fail because of a math overflow in `{_transferVotingUnits}`. An override could be used to further restrict the total supply (to a lower value) if additional logic requires it.

## Proof of Concept
The `_update` function in the ERC20Votes implementation enforces a total supply of Uint208 and this is responsible for transferring Voting Units.
```function _update(address from, address to, uint256 value) internal virtual override {
        super._update(from, to, value);
        if (from == address(0)) {
            uint256 supply = totalSupply();
            uint256 cap = _maxSupply();
            if (supply > cap) {
                revert ERC20ExceededSafeSupply(supply, cap);
            }
        }
        _transferVotingUnits(from, to, value);
    }
```
The approval of more than Uin208 in `ERC20ProxyDelegator` without overrides breaks this invariant supply cap.
```solidity
contract ERC20ProxyDelegator {
    constructor(ERC20Votes _token, address _delegate) {
        _token.approve(msg.sender, type(uint256).max); 
        _token.delegate(_delegate);
    } 
}
```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Due to the maximum token supply restrictions of `ERC20Votes` implementation, consider approving the contract to spend a maximum of `type(Uint208).max`


## Assessed type

Under/Overflow
No address validation can lead to unexpected behaviour
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L65-L116


# Vulnerability details

### Background
With the implementation of the `ERC20Multidelegate` contract, it will be possible to delegate your voting power to multiple recipients in one transaction. A user can call `ERC20MultiDelegate.delegateMulti` to initiate this multi-delegation:
```javascript
source: contracts/ERC20MultiDelegate.sol

function delegateMulti(
        uint256[] calldata sources,
        uint256[] calldata targets,
        uint256[] calldata amounts
    ) external {
        _delegateMulti(sources, targets, amounts);
    }
```
The parameters inputs are all `uint256[]`. This means that a user that inputs `[address]`, it will be automatically typecasted to an `[uint256]`. 

In `ERC20MultiDelegate._delegateMulti`, in the for loop, the addresses of the sources and targets will be typecasted from `uint256` -> `uint160` -> `address`

After the loop in `ERC20MultiDelegate._delegate` is finished, it call `ERC1155._burnBatch` and/or `ERC1155._mintBatch`. These functions will either use `sources` as the parameter for `ids` or `targets` as the parameter `ids`.

Here lays the problem.  These `sources` and `targets` used in `_burnBatch` and `_mintBatch` are different that the `sources` and `targets` used in the loop that happens before, this is the for loop:
```javascript
source: contracts/ERC20MultiDelegate.sol

function _delegateMulti(..) {
//.. ommitted code
		for (
            uint transferIndex = 0;
            transferIndex < Math.max(sourcesLength, targetsLength);
            transferIndex++
        ) {
            address source = transferIndex < sourcesLength
                ? address(uint160(sources[transferIndex]))
                : address(0);
            address target = transferIndex < targetsLength
                ? address(uint160(targets[transferIndex]))
                : address(0);
            uint256 amount = amounts[transferIndex];
        }
//.. ommitted code
}
```
 In the loop `sources` and `targets` are typecasted from `uint256` -> `uint160` -> `address`. This means the `sources` in the for loop will be different than `sources` after the loop, leading to different `ids` being used.
 This will lead to delegating your voting power to an address while getting different `ids` on the `ERC1155` that you received when `_mintBatch` is called.
### Proof of Concept
I created a POC:
```javascript
// Put this in test/delegatemulti.js
// and run using:
// yarn test test/delegatemulti.js
  describe('delegate to non-address', () => {
    it.only('should be able to delegate to non-address and it will go to an address', async () => {
      // Deployer will be delegating the votes
      // Approve 3000 tokens
      await token.approve(multiDelegate.address, 3000);
      // addressDelegateTo = the original address, address1 has a 1 added at the beginning and address 2 has a two added in the beggining 
      const addressDelegateTo
Possibility of security vulnerabilities introduced by creating ERC20ProxyDelegator instances on the fly using static salt values
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L186
https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L210


# Vulnerability details

## Impact
Security risks associated with deploying proxy contracts via deterministic addresses that can be easily calculated.

In **deployProxyDelegatorIfNeeded**, in the case that **extcodesize(proxyAddress) == 0**, then a proxy contract is instantiated ad hoc via **new ERC20ProxyDelegator{salt: 0}(token, delegate)**.

Similar to Issue 2, not being able to verify the existence and/or security of managed **ERC20ProxyDelegator** contract instances can lead to various potential exploits and errors. However, in this Issue, unlike in Issue 2, the severity is even worse because the main fear is not of centralization risk where a privileged actor, like an ENS deployer, might be the potential culprit; this vulnerability is opened up to a **sophisticated bad actor** that is looking to monitor on-chain for pre-determined address and act to exploit in some way. This can completely compromise the efficacy and trust of the **ERC20MultiDelegate** contract’s expected functionality and security.

## Proof of Concept
The address of this proxy contract can be pre-known, via invoking **retrieveProxyContractAddress(token, delegate)**. Even though this deployment uses the non-deterministic **CREATE2** op via the keccak256 hash of bytes1(0xff), address(this), uint256(0), and keccak256(bytecode) (within the **retrieveProxyContractAddress** logic), the address can be easily pre-calculated ahead of time by attackers who may be pre-calculating proxy contract address before they’re deployed and monitoring the blockchain waiting for proxy contract with those addresses to be deployed. There are many known ways attackers can exploit this, potentially including taking ownership of the newly-deployed proxy contract and putting malicious code onto the newly-deployed proxy contract. 

## Tools Used
Solidity/JS/Hardhat 

## Recommended Mitigation Steps
Create proxy contract instances on the fly instead using a scheme that utilizes more non-deterministic addresses, perhaps by still using **CREATE2** but introducing some verifiable and secure randomness to the salt parameter, for example. This could prevent attackers that may be monitoring for deployed contracts at addresses they can anticipate ahead of time from exploiting the efficacy sanctity of these deployed **ERC20ProxyDelegator** contracts in various possible ways.


## Assessed type

Other
No validation allows unauthorized voting power transfer by any user.
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L57-L63


# Vulnerability details

## Impact

There is no check that the `msg.sender` is allowed to delegate votes on behalf of the sources. Any user could call `delegateMulti` and transfer voting power from other addresses.

There should be a `require` statement to ensure `msg.sender` owns the tokens they are delegating.

## Proof of Concept

The issue occurs in the `delegateMulti()` function, which does not check that `msg.sender` is authorized to delegate the tokens specified in the sources array. 

**[ERC20MultiDelegate.sol#L57-63](https://github.com/code-423n4/2023-10-ens/blob/ed25379c06e42c8218eb1e80e141412496950685/contracts/ERC20MultiDelegate.sol#L57-L63)**
```solidity
function delegateMulti(
    uint256[] calldata sources,
    uint256[] calldata targets,
    uint256[] calldata amounts
) external {

    // Add a require statement here:
    require(msg.sender == ownerOf(sources), "Not authorized");
    
    _delegateMulti(sources, targets, amounts);
}
```

The `ownerOf()` call would check that `msg.sender` owns the tokens they are trying to delegate. Without this, any user can call `delegateMulti` and transfer voting rights from other addresses without authorization.

Adding this require statement before calling the internal `_delegateMulti()` function would prevent unauthorized delegation by ensuring proper token ownership.

Due to missing ownership validation of the source tokens. Let me provide an in-depth explanation:

The key issue is that `delegateMulti()` accepts an array of source addresses to withdraw voting power from, but there is no check that `msg.sender` actually owns those tokens. 

For example:

```solidity
function delegateMulti(
  address[] calldata sources, 
  address[] calldata targets,
  uint[] calldata amounts
) external {

  // missing validation!!

  _delegateMulti(sources, targets, amounts); 
}
```

This means any user could call `delegateMulti()` and freely withdraw voting power from arbitrary addresses in the sources array.

The critical missing validation is:

```soldity
require(msg.sender == ownerOf(source), "Not authorized"); 
```

This would verify `msg.sender` owns each source address before delegating.

Without this ownership check, several risks arise:

- Attackers can steal voting power from token holders without consent
- Users could have their votes delegated to malicious delegates without approval
- Token holders may lose governance rights if voting power is drained to other addresses

This completely subverts the intended security model of only allowing delegation of owned voting power. 

The lack of `msg.sender` authorization validation against the sources array is a critical vulnerability that would allow unauthorized and likely malicious delegation activity. Adding an explicit ownership check using `require()` and `ownerOf()` is needed to prevent this high severi