xanoutas/solidity-security-findings huggingface dataset:
Malicious actor can divert delegate votes.
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The delegateMulti is an external function that can be called by anybody.
A malicious actor can divert delegate tokens to personal addresses by calling "delegateMulti" function, allowing the malicious actor to gain surplus amount of tokens and then influencing voting consensus.
## Proof of Concept
Malicious actors, more effectively with insider info can front-run transactions during multiDelegation, by passing their own set of personal addresses as the target addresses causing an unprecedented amount of voting power been possessed by one individual. 

function delegateMulti is an external function that calls the internal 'delegateMulti' function  
```solidity
   function delegateMulti(
        uint256[] calldata sources,
        uint256[] calldata targets,
        uint256[] calldata amounts
    ) external {
        _delegateMulti(sources, targets, amounts);
    }
```
Internal "delegateMulti" called by the external delegateMulti function processes malicious transactions because of lack of access control on the external delegateMulti.
```solidity
function _delegateMulti(
        uint256[] calldata sources,
        uint256[] calldata targets,
        uint256[] calldata amounts
    ) internal {
        uint256 sourcesLength = sources.length;
        uint256 targetsLength = targets.length;
        uint256 amountsLength = amounts.length;

        require(
            sourcesLength > 0 || targetsLength > 0,
            "Delegate: You should provide at least one source or one target delegate"
        );

        require(
            Math.max(sourcesLength, targetsLength) == amountsLength,
            "Delegate: The number of amounts must be equal to the greater of the number of sources or targets"
        );

        // Iterate until all source and target delegates have been processed.
        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];

            if (transferIndex < Math.min(sourcesLength, targetsLength)) {
                // Process the delegation transfer between the current source and target delegate pair.
                _processDelegation(source, target, amount);
            } else if (transferIndex < sourcesLength) {
                // Handle any remaining source amounts after the transfer process.
                _reimburse(source, amount);
            } else if (transferIndex < targetsLength) {
                // Handle any remaining target amounts afte
Delegation process fails because source delegator addresses have not been minted previously as erc1155 tokens to multiDelegate contract.
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

## Impact
MultiDelegate contract assumes all Source delegate addresses have been minted to the erc1155 token and proceeds to delegate votes from the Soucre addresses.
Impact is critical because the whole delegation process is affected.

## Proof of Concept
The MultiDelegate contract after deployment presumes all source addresses have been minted, but this might not be the case often, especially when processing the first set of delegation activities from the contract, because the source addresses during that time have not even be minted into MultiDelegate contract. And because the source addresses don't have a minted record in the contract, a cascade of function fails leading to a failed delegation.

Chain reaction
The function "getBalanceForDelegate" which looks up balance for the source delegates reverts because the source delegate has no minted record in the contract
```solidity 
 function getBalanceForDelegate(
        address delegate
    ) internal view returns (uint256) {
        return ERC1155(this).balanceOf(msg.sender, uint256(uint160(delegate)));
    }
```
The delegation process subsequently fails because the contract bears no record of the source delegate balance
```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);
    }
```
Steps to recreate
1. Source addresses that have been individually delegated  or who are valid delegates are passed in the _delegateMulti function for delegation the first time after contract contract deployment.

2. Because the contract has not previously minted the source delegates, delegation fails.

## Tools Used
VsCode, Manual review
## Recommended Mitigation Steps
Source delegates should be confirmed to be minted first as erc1155 tokens of the multiDelegate contract before delegation.
If not minted, authorized minting souce of delegates should be processed by the admin.





## Assessed type

Other
proxyAddress is not returned if the proxy contract has not been deployed for the target address.
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
This is high, cause this is expected to happen frequently because target address are reckoned not to often have already deployed proxy addresses and required amount of votes will not be delegated to residual target addresses to be processed through the "createProxyDelegatorAndTransfer" function because new proxy address is not returned.
## Proof of Concept
The function "deployProxyDelegatorIfNeeded" is used to retrieve "proxyAddress" for the targets and also to deploy a new proxy contract if the target address doesn't have one.
```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;
}
```

Though the function successfully retrieves the proxy address if a target has one already, it however fails to return the proxy address of the newly deployed proxy addresses.
Predictably, the "_processDelegation" function successfully delegates even though new proxy addresses are not returned because it also calls the "transferBetweenDelegators" functions which would retrieve the newly created proxy address before processing the trnx.
```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);
    }
```
On the other hand, when residual targets transfers are processed through the "createProxyDelegatorAndTransfer" method. The internal function; "deployProxyDelegatorIfNeeded" only retrieves the old proxy Addresses and doesn't for newly created proxy contracts of the targets causing the delegation process to fail.
```solidity
    function createProxyDelegatorAndTransfer(
        address target,
        uint256 amount
    ) internal {
        address proxyAddress = deployProxyDelegatorIfNeeded(target);
        token.transferFrom(msg.sender, proxyAddress, amount);
    }
```

## Tools Used
Vscode, Manual review.
## Recommended Mitigation Steps
The retrieveProxyContractAddress should be called to retrieve the new proxy Delegator address and passed into the proxyAddress variable.
```solidity
function deployProxyDelegatorIfNeeded(
    address delegate
) internal returns (address) {
    address proxyAd
DoS Vulnerability due to Unbounded Looping
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
There is a potential for a DoS vulnerability due to unbounded looping over arrays of unknown size. Specifically, the contract processes delegation transfers using a loop that iterates over arrays (`sources`, `targets`, and `amounts`) of user-provided length. If the arrays are excessively large, the gas cost of executing the loop could exceed the block gas limit, causing transactions to fail and leading to a DoS scenario. An attacker could exploit this by submitting transactions with large arrays, potentially draining all user gas and causing legitimate transactions to fail.

## Proof of Concept
1. An attacker creates a large array of `sources`, `targets`, and `amounts` to be processed in the `delegateMulti` function.
2. The attacker submits a transaction calling the `delegateMulti` function with the large arrays as parameters.

```solidity
File: contracts/ERC20MultiDelegate.sol

58: function delegateMulti(
59:        uint256[] calldata sources,
60:        uint256[] calldata targets,
61:        uint256[] calldata amounts
62:    ) external {
63:        _delegateMulti(sources, targets, amounts);
64:    }

```

## Tools Used
VS Code

## Recommended Mitigation Steps
To mitigate this vulnerability, consider implementing a design pattern where the contract processes a limited number of elements in each transaction, preventing excessive gas consumption. For example, you can implement pagination or chunking to limit the number of elements processed in a single transaction. By breaking down the processing into smaller units, the gas cost can be controlled, and the contract becomes resistant to DoS attacks. Additionally, consider implementing a maximum limit for the number of elements that can be processed in a single transaction to prevent abuse.

Here's an example of how you can modify the `_delegateMulti` function to process a limited number of elements at a time:

```solidity
function _delegateMulti(
    uint256[] calldata sources,
    uint256[] calldata targets,
    uint256[] calldata amounts
) internal {
    uint256 sourcesLength = sources.length;
    uint256 targetsLength = targets.length;
    uint256 amountsLength = amounts.length;

    require(
        sourcesLength > 0 || targetsLength > 0,
        "Delegate: You should provide at least one source or one target delegate"
    );

    require(
        Math.max(sourcesLength, targetsLength) == amountsLength,
        "Delegate: The number of amounts must be equal to the greater of the number of sources or targets"
    );

    // Check if total gas cost of execution exceeds block gas limit
    require(gasleft() >= sourcesLength * 50000, "Delegate: Gas limit exceeded");

    // Iterate until all source and target delegates have been processed.
    for (
        uint
Malicious user can steal tokens of other users
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L104
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#L17


# Vulnerability details

## Impact
The delegateMulti() function, if needed, deploys a proxy for a target. The proxy, in its constructor, grants the maximum allowance for a _token to msg.sender. This could become problematic if a malicious user decides to front-run the call to delegateMulti(). In such a scenario, an attacker would deploy a proxy and obtain the maximum allowance. Subsequently, they can transfer tokens from the proxy to themselves
 
## Proof of Concept
```
constructor(ERC20Votes _token, address _delegate) {
        _token.approve(msg.sender, type(uint256).max);
        _token.delegate(_delegate);
}
```
```
if (bytecodeSize == 0) {
            new ERC20ProxyDelegator{salt: 0}(token, delegate);
            emit ProxyDeployed(delegate, proxyAddress);
}
```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider setting a specific and limited allowance that is sufficient for the intended functionality


## Assessed type

Other
Potential for Failed Transactions and Network Disruption due to Lack of Proper Balance Checks and Error Handling
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
In the high-level overview of your contract, if a user with insufficient balance attempts to execute the delegateMulti function multiple times, and the assert statement evaluates to false, the entire transaction will fail, and any gas consumed in that failed transaction will not be refunded.
Without a balance check, users can attempt to delegate more tokens than they actually have in their account. If the contract doesn't validate this, it can lead to failed transactions, and the user's tokens may get stuck in an inconsistent state and as we are using assert and not require in case of getting error 
In the worst case if a bad user calls the function several times (or using a flash loans that several times) it can cause the contract pause running out of gas and it may cause possible exploits to other contracts as well

## Proof of Concept

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


delegateMulti => _delegateMulti => _processDelegation => assert(amount <= balance);

Not checking the user balance and not having a good error handling may possibly cause several issues as mentioned earlier

    function delegateMulti(
        uint256[] calldata sources,
        uint256[] calldata targets,
        uint256[] calldata amounts
    ) external {
        // doesnt check for address zero and balance
        _delegateMulti(sources, targets, amounts);
    }


   function _processDelegation(
        address source,
        address target,
        uint256 amount
    ) internal {
        uint256 balance = getBalanceForDelegate(source);
        // we can use require instead
        assert(amount <= balance);

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

        emit DelegationProcessed(source, target, amount);
    }




## Tools Used

Manual review

## Recommended Mitigation Steps

Using require in this context is not only more appropriate but also provides better feedback to users in case of an invalid input, as it returns a clear error message that can be helpful for debugging and understanding why the transaction failed.

Its better to use this peace of code in the delegateMulti before passing the args to the _delegateMulti to save more gas and secure the contract 

uint256 balance = getBalanceForDelegate(source);
require(amount <= balance, "Insufficient balance for delegation");




## Assessed type

Invalid Validation
_approve function, if the allowance passed in is type(uint256).max, nothing happens.  because the max allowance attainable is type(uint256).max - 1.
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

The _approve function in the ERC20ProxyDelegator contract seems to not work as expected when the allowance passed in is type(uint256).max. The expectation would be to set the maximum allowance, but instead, nothing happens. This is due to the maximum allowance attainable being type(uint256).max - 1, resulting in an allowance set to zero. The improper handling of this situation affects the functioning of the main contract ERC20MultiDelegate, making its operation unreliable when dealing with maximum value allowances.

Steps to Reproduce:
Deploy ERC20ProxyDelegator contract through deployProxyDelegatorIfNeeded with a delegate address.
The constructor attempts to _approve the msg.sender (the ERC20MultiDelegate contract) with an allowance of type(uint256).max.
Observe that the resulting allowance is not set as expected (should be type(uint256).max but is zero instead).

The identified vulnerability in the ERC20ProxyDelegator contract has significant implications for the operation and reliability of the ERC20MultiDelegate contract and the overall system it supports. In the normal course of operation, the ERC20ProxyDelegator contract is deployed dynamically through the deployProxyDelegatorIfNeeded function, wherein allowances are set to facilitate proper delegation of tokens. Given that the _approve function fails to set the correct allowances when type(uint256).max is specified, this disrupts the expected workflow of the system. The ERC20MultiDelegate contract, acting as the msg.sender and reliant on these allowances, would consequently be unable to function as designed

## Tools Used
remix

## Recommended Mitigation Steps

change to:

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


## Assessed type

ERC20
Unrestricted transferFrom Usage Could Lead to Token Loss
Audit: 2023-10-ens-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
An attacker could potentially drain the ERC20 allowances of the from address, leading to a loss of tokens. This could occur without the knowledge or consent of the from address, as the transferFrom function does not require the from address to be the msg.sender.
## Proof of Concept
The `transferFrom` function is used to move tokens from one address to another. It requires approval from the `from` address, which is typically given by calling the approve function of the ERC20 token contract. In the provided code, the `transferFrom` function is used in several places where the `from` parameter is not the `msg.sender`. For example, in the `transferBetweenDelegators` function:
```solidity
function transferBetweenDelegators(
    address from,
    address to,
    uint256 amount
) internal {
    address proxyAddressFrom = retrieveProxyContractAddress(token, from);
    address proxyAddressTo = retrieveProxyContractAddress(token, to);
    token.transferFrom(proxyAddressFrom, proxyAddressTo, amount);
}
```
In this case, the `from` address is a proxy contract address, not the `msg.sender`. If the access control for this function is not properly implemented, it could potentially allow an attacker to drain ERC20 allowances.
## Possible attack Scenario:
- Let's assume that Alice is a user of this contract and she has approved the contract to spend tokens on her behalf. She has also delegated some tokens to a proxy contract, which is controlled by the contract.
- An attacker, Eve, discovers that the contract does not properly implement access controls for functions that use transferFrom with a from parameter that's not the msg.sender. Eve realizes that she can call these functions to move tokens from Alice's proxy contract to any address she wants.
- Eve decides to exploit this vulnerability. She calls the transferBetweenDelegators function, specifying Alice's proxy contract as the from address and her own address as the to address. She also specifies a large amount of tokens to be transferred.
- Because the contract does not check that the caller is authorized to move tokens from the from address, the transaction succeeds. Eve is able to drain all of the tokens that Alice had delegated to the proxy contract, transferring them to her own address.
- Alice is unaware of this transaction until she checks her token balance and finds that all of her delegated tokens are gone. She has no way of recovering the tokens, as they have been transferred to Eve's address and are now under Eve's control.
## Tools Used
Manual
## Recommended Mitigation Steps
Add a requirement that the caller of the function must be the owner of the contract or have a specific role. This can be achieved by adding a require statement at the beginning of the function that checks if msg.sender is the owner or has the