xanoutas/solidity-security-findings huggingface dataset:
Checks in `isContract()` can be bypassed using CREATE2 which can break several functionalities
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/LibAddress.sol#L11-L16
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L48-L53
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L120-L125


# Vulnerability details

## Proof of Concept

https://consensys.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/extcodesize-checks/

The function `isContract()` just checks code length at the address provided.

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/LibAddress.sol#L11-L16

```
  11-16: function isContract(address account) internal view returns (bool) { 
    uint256 csize;
    // solhint-disable-next-line no-inline-assembly++
    assembly { csize := extcodesize(account) } 
    return csize != 0;
  }
```

Attacker can interact with the system and selfdestruct his contract, and with help of **CREATE2** recreate it at same address when he needs to interact with the system again.

Several functionalities will break and will provide wrong results. For instance `depositFor()` function makes use of `isContract()` as follows:

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L48-L53

```
function depositFor(address paymasterId) public payable {
        require(!Address.isContract(paymasterId), "Paymaster Id can not be smart contract address");
        require(paymasterId != address(0), "Paymaster Id can not be zero address");
        paymasterIdBalances[paymasterId] += msg.value;
        entryPoint.depositTo{value : msg.value}(address(this));
    }
```

As it can be observed `paymasterId` can not be a smart contract. However an attacker can interact with the system and selfdestruct his contract, pass the require check ( `require(!Address.isContract(paymasterId)`) and with help of **CREATE2** recreate it at same address when he needs to interact with the system again.

similarly the following can also produce unexpected results:

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L120-L125

```
    120-125: function updateImplementation(address _implementation) external mixedAuth {
        require(_implementation.isContract(), "INVALID_IMPLEMENTATION");
        _setImplementation(_implementation);
        // EOA + Version tracking
        emit ImplementationUpdated(address(this), VERSION, _implementation);
    }
```


## Recommended Mitigation Steps

A whitelist of valid addresses can be maintained.
`execFromEntryPoint` will always revert.
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L489-L492
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460


# Vulnerability details

```
    function execute(address dest, uint value, bytes calldata func) external onlyOwner{
        _requireFromEntryPointOrOwner();
        _call(dest, value, func);
    }

    function execFromEntryPoint(address dest, uint value, bytes calldata func, Enum.Operation operation, uint256 gasLimit) external onlyEntryPoint returns (bool success) {        
        success = execute(dest, value, func, operation, gasLimit);
        require(success, "Userop Failed");
    }
```

`execFromEntryPoint` is a function that can only be accessed by entrypoint. When entrypoint call the function, `execute` is called. `execute`, however, can only be called by the owner. As the function has `_requireFromEntryPointOrOwner()`, it seems that entrypoint can also be called, but `execute` is using the onlyOwner modifier, so it cannot be accessed unless it is an owner. 




## Tools Used
Manual audit

## Recommended Mitigation Steps
`execute` should be modified to use the `mixedAuth` modifier as follows. Even if we delete `_requireFromEntryPointOrOwner();` the owner can be accessed via `mixedAuth`.

```
    function execute(address dest, uint value, bytes calldata func) external mixedAuth{
        _call(dest, value, func);
    }
```
No zero address check for withdrawAddress
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L536-L538


# Vulnerability details

## Impact
There is no zero address check for withdrawAddress which might lead to loss of funds

## Proof of Concept
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L536-L538
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L115-L122

Here SmartAccount.sol and even the StakeManager.sol of EntryPoint.sol don't check for zero address

## Tools Used
Manual Review
## Recommended Mitigation Steps
Add a zero address check
`validatePaymasterUserOp` allows for signature malleability
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L107


# Vulnerability details

## Impact
The `validatePaymasterUserOp` allows for both 64 and 65 sig lengths:

`require(sigLength == 64 || sigLength == 65, "VerifyingPaymaster: invalid signature length in paymasterAndData");`

This might result in signature malleability depending on which ECDSA version is used.

## Proof of Concept
As already above described, the `validatePaymasterUserOp` function lays the first step for potential signature malleability due to it accepting a length of 64 as well. Depending on the used version of `ECDSA.sol` this will result in a potential vulnerability. We are aware that the deployment will most probably automatically use the fixed `ECDSA.sol` contract, however, if this codebase is ever forked with an older `ECDSA.sol` version, the vulnerability will occur, while this could be easily fixed. Hence the medium risk rating.

## Tools Used
VSCode

## Recommended Mitigation Steps
Consider limiting the `sigLength` acceptance to 65 in order to prevent potential signature malleabilities.
amount has to be bigger than 0
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L55


# Vulnerability details

## Impact
Nothing critical, but it is the best practice. The transaction will go through and call withdraw if you input 0.


## Proof of Concept
        function withdrawTo(address payable withdrawAddress, uint256 amount) public override {
        require(amount > 0, "not enough");   //changes
        uint256 currentBalance = paymasterIdBalances[msg.sender];
        require(amount <= currentBalance, "Insufficient amount to withdraw");
        paymasterIdBalances[msg.sender] -= amount;
        entryPoint.withdrawTo(withdrawAddress, amount);
        }


## Tools Used
hand
## Recommended Mitigation Steps

add      require(amount > 0, "not enough");   to the function
Wrongly added modifier to `execute` and `executeBatch`
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460


# Vulnerability details

## Impact
`execute` and `executeBatch` are never callable by `entryPoint`

## Proof of Concept
Currently, the `execute` and `executeBatch` functions are most probably meant to be called by `entryPoint` or `owner`:

`_requireFromEntryPointOrOwner();`

However, the `onlyOwner` modifier effectively prevents these functions from ever being called by `entryPoint`, limiting the contracts functionalities.

## Tools Used
VSCode

## Recommended Mitigation Steps
Consider removing the `onlyOwner` modifier from `execute` and `executeBatch`
Reverting all the UserOperation in the mempool by front-running the bundler and not refunding the gas
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/5df2e8f8c0fd3393b9ecdad9ef356955f07fbbdd/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L68


# Vulnerability details

## Impact

***In summary, a malicious user can add his UserOperation to the mempool of bundler, and then by front-running the bundler and withdrawing the gas refund required for his operation to be executed, he can cause that the bundler lose huge gas. If his operation is going to be refunded by his smart account, then by front-running and withdrawing his deposit, all the gas consumed for all ops account prepayment validation will be deducted from the bundler without refund. If his operation is going to be refunded by paymaster, then by front-running and withdrawing his deposit as paymaster, all the gas consumed for all ops account prepayment validation and paymaster prepayment validation will be deducted from the bundler without refund.***

## Proof of Concept

A bundler is going to relay UserOperation to the EntryPoint contract. The bundler picks UserOperations from the high-level UserOperation mempool (which is not the same as the regular transaction mempool). Suppose there are 50 UserOpertions from various sources (ops1 for user1, ops2 for user2, ...., and ops50 for Bob as a malicious user). So, the function `handleOps` will be called to validate and execute these operations.
https://github.com/code-423n4/2023-01-biconomy/blob/5df2e8f8c0fd3393b9ecdad9ef356955f07fbbdd/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L68

Please note that the function `simulateValidation` is to check whether the account and paymaster prepayment are valid before the function `handleOps` is called.
https://github.com/code-423n4/2023-01-biconomy/blob/5df2e8f8c0fd3393b9ecdad9ef356955f07fbbdd/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L226

There are two scenarios:

### First Scenario:

Bob has already provided the required gas refund for his operation (ops50) by calling the function `depositTo(address account)` in which the `account` is the address of Bob's smart account. So, we will have `deposits[Bob's account].deposit = gas refund`.

https://github.com/code-423n4/2023-01-biconomy/blob/5df2e8f8c0fd3393b9ecdad9ef356955f07fbbdd/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L48

Bob has sets `paymaster = address(0)` in his ops50 that means the smart account is going to refund the gas not the paymaster. Since there is enough deposit in the EntryPoint contract by Bob, the simulation of validation shows that ops50 is a valid operation. So, the function `handleOps` will be called. 

Bob, notices this function call in the mempool, and applies front-run attack and calls the function `execute`.

https://github.com/code-423n4/2023-01-biconomy/blob/5df2e8f8c0fd3393b9ecdad9ef356955f07fbbdd/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460

He provides the followi
`refundReceiver` will receive less tokens than desired
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L264


# Vulnerability details

## Impact
Due to rounding issues, the `recipient` will receive less tokens than expected

## Proof of Concept

During divisions, solidity always rounds down. This can become especially an issue if it rounds down in favor of the user and if the multipliers are not very high. Due to that issue, the `feeRecipient` might receive less fees than expected.


## Tools Used
VSCode

## Recommended Mitigation Steps
Consider always using a multiplier e.g `1e24` for divisions in solidity
methods used by EntryPoint has `onlyOwner` modifier
Audit: 2023-01-biconomy-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460-L461
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L465-L466


# Vulnerability details

## Description
`execute` and `executeBatch` in `SmartAccount.sol` can only be called by owner, not EntryPoint:

```javascript
File: SmartAccount.sol

460:    function execute(address dest, uint value, bytes calldata func) external onlyOwner{
461:        _requireFromEntryPointOrOwner();
462:        _call(dest, value, func);
463:    }
464:
465:    function executeBatch(address[] calldata dest, bytes[] calldata func) external onlyOwner{
466:        _requireFromEntryPointOrOwner();
467:        require(dest.length == func.length, "wrong array lengths");
468:        for (uint i = 0; i < dest.length;) {
469:            _call(dest[i], 0, func[i]);
470:            unchecked {
471:                ++i;
472:            }
473:        }
474:    }
```

From [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337):

> - **Call the account with the `UserOperation`’s calldata.** It’s up to the account to choose how to parse the calldata; an expected workflow is for the account to have an execute function that parses the remaining calldata as a series of one or more calls that the account should make.

## Impact
This breaks the interaction with EntryPoint

## Proof of Concept
The reference implementation has both these functions without any onlyOwner modifiers:

https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccount.sol#L56-L73
```javascript
56:    /**
57:     * execute a transaction (called directly from owner, not by entryPoint)
58:     */
59:    function execute(address dest, uint256 value, bytes calldata func) external {
60:        _requireFromEntryPointOrOwner();
61:        _call(dest, value, func);
62:    }
63:
64:    /**
65:     * execute a sequence of transaction
66:     */
67:    function executeBatch(address[] calldata dest, bytes[] calldata func) external {
68:        _requireFromEntryPointOrOwner();
69:        require(dest.length == func.length, "wrong array lengths");
70:        for (uint256 i = 0; i < dest.length; i++) {
71:            _call(dest[i], 0, func[i]);
72:        }
73:    }
```

## Tools Used
vscode

## Recommended Mitigation Steps
Remove `onlyOwner` modifier from `execute` and `executeBatch`
Users can avoid slashing losses by front-running
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L219-L224


# Vulnerability details

If any of the validators run by the Renzo protocol are slashed, or if AVS operators delegated to are slashed, the slashing losses should be borne by all ezETH token holders. However, it takes time for the slashing losses to reflect in the TVL, as validator slashes need to be proven in Eigen Pod first using a beacon chain state root. During this time, users can front-run the TVL changes and withdraw their funds from Renzo to avoid losses.

To address this issue, a withdrawal delay was introduced. However, the `amountToRedeem` is currently calculated during the withdrawal initiation itself instead of calculating it in the claim function. So users can still avoid losses by front-running TVL updates.

## Proof of Concept

1. Current TVL of the protocol is 100 ETH and there are 100 ezETH in supply.
2. So current exchange rate is 1 ETH/ezETH.
3. Now one of the validator gets slashed by 20 ETH.
4. So current TVL is 8O ETH and exchange rate is 0.8 ETH/ezETH.
5. But the current TVL is still reported to be 100 ETH as it takes time for EigenPodManager to update the podShares of OperatorDelegator as it only reduces podShares once someone proves to the EigenPod that the validator is slashed on beacon chain using beacon state root.
6. So the users can exit the protocol at a higher exchange rate than intended exchange rate.

This creates a race condition, where users capable of exiting earlier can do so without incurring losses.

## Impact
Users can avoid validator and AVS slashing losses 

## Tools Used

## Recommended Mitigation Steps

Instead of calculating `amountToRedeem` in withdraw function itself calculate it in the claim function.








## Assessed type

MEV
Stakers could frontrun `EigenPod.verifyBalancUpdates()` to avoid any validator penalities
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206


# Vulnerability details

## Impact
If the Pod Owner's beacon chain ETH balance decreases, which could be due to slashing or penality, someone can provide proof of this to the `EigenPod.verifyBalanceUpdates()` function to record the beacon chain balance updates.

As a result, `podOwnerShares[podOwner]` will be deduct [here](https://github.com/Layr-Labs/eigenlayer-contracts/blob/15b679b08e7a3589ff83a5e84076ca4e0a00ec0b/src/contracts/pods/EigenPod.sol#L223), which directly impacts Renzo since its total TVL drops,

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Delegation/OperatorDelegator.sol#L338
```solidity
    function getStakedETHBalance() external view returns (uint256) {
        // accounts for current podOwner shares + stakedButNotVerified ETH + queued withdraw shares
        int256 podOwnerShares = eigenPodManager.podOwnerShares(address(this));
        return
            podOwnerShares < 0
                ? queuedShares[IS_NATIVE] + stakedButNotVerifiedEth - uint256(-podOwnerShares)
>@              : queuedShares[IS_NATIVE] + stakedButNotVerifiedEth + uint256(podOwnerShares);
    }
```
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L329
```solidity
    function calculateTVLs() public view returns (uint256[][] memory, uint256[] memory, uint256) {
	...snip...

            // Get the value of native ETH staked for the OD
>@          uint256 operatorEthBalance = operatorDelegators[i].getStakedETHBalance();

            // Save it to the array for the OD
            operatorValues[operatorValues.length - 1] = operatorEthBalance;

            // Add it to the total TVL for this OD
            operatorTVL += operatorEthBalance;

            // Add it to the total TVL for the protocol
            totalTVL += operatorTVL;

	...snip...
        return (operatorDelegatorTokenTVLs, operatorDelegatorTVLs, totalTVL);
    }
```
Stakers could front-run these updates by requesting a withdrawal, avoiding any penalties. Let's see how.

## Proof of Concept

- Before `verifyBalancUpdates()` being called, stakers send a `withdrawQueue.withdraw()` txn which allow them to redeem their ezETH shares token before tvl changes. 

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L229
```solidity
        // calculate totalTVL
        (, , uint256 totalTVL) = restakeManager.calculateTVLs();

        // Calculate amount to Redeem in ETH
        uint256 amountToRedeem = renzoOracle.calculateRedeemAmount(
            _amount,
            ezETH.totalSupply(),
            totalTVL
        );
```

This `amountToRedeem` is cached to `withdrawRequests[staker]` and is seperated from the totalTVL for future claim.

- `EigenPod.verifyBal
Stakers Can Avoid Validators Slashing Penalties By Frontrunning Eigen Layer Updates
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/Layr-Labs/eigenlayer-contracts/blob/90a0f6aee79b4a38e1b63b32f9627f21b1162fbb/src/contracts/pods/EigenPod.sol#L188-L224
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206-L263


# Vulnerability details

## Impact

Changes to the actual balance of validators are updated when an [EigenPod::verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/90a0f6aee79b4a38e1b63b32f9627f21b1162fbb/src/contracts/pods/EigenPod.sol#L188-L224) is called on an EigenPod. The slashing of an EigenPod is therefore known before it is updated in the EigenLayer system.

A malicious user can abuse this by front-running the [verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/90a0f6aee79b4a38e1b63b32f9627f21b1162fbb/src/contracts/pods/EigenPod.sol#L188-L224) call to circumvent the slashing penalty.

+ To Illustrate:

A user can monitor the validators and request a withdrawal via [WithdrawQueue::withdraw](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206-L263) function when a validator is slashed to front-run calls to [verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/90a0f6aee79b4a38e1b63b32f9627f21b1162fbb/src/contracts/pods/EigenPod.sol#L188-L224), hence claiming more ether than they are entitled to.
This is because the total value locked for the system has still not accounted for the slashing that happened.

For example:
Let's analyze this issue by observing two users in the system, Bob and Alice who own 5 ezETH each.
Assuming the following simplified state, with just one validator:
current ezETH supply = 32e18
current protocol TVL = 32 ether

If the validator is slashed for 16 eth, and Bob front runs the call to the [EigenPod::verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/90a0f6aee79b4a38e1b63b32f9627f21b1162fbb/src/contracts/pods/EigenPod.sol#L188-L224) function to request a withdrawal via [WithdrawQueue::withdraw](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206-L263) function, to burn all of his ezETH for ether, the amount of ether Bob receives is calculated [here](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Oracle/RenzoOracle.sol#L152-L164), as:
redeem amount = current TVL * ezTH to burn / ezETH supply 
= 32e18 * 5e18 / 32e18 ==> 5e18

Bob will now be eligible to claim 5 ether for his 5 ezETH after the cool-down period, via a call to [WithdrawQueue::claim](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206-L263) function.

Current State after Bob's withdrawal:
ezETH Supply = 32e18 - 5e18 ==> 27e18
TVL = 32 ether - 5 ether = 27 ether ==> 27 ether