xanoutas/solidity-security-findings huggingface dataset:
Ability to bypass the despositFor() function's check and to set the PaymasterId to the address of a smart contract
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#L48-L53
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/libs/LibAddress.sol#L11-L16


# Vulnerability details

## Impact
The "depositFor()" function verifies that the PaymasterId address is not a smart contract before allowing it to continue and to deposit. 
However, the extcodesize can be bypassed easily, which allows an attacker to set the PaymasterId address to the address of a smart contract and to deposit with it.


## Proof of Concept
It is possible to bypass the "assembly { csize := extcodesize(account) } return csize != 0;" check by calling the depositFor() function from the constructor of a smart contract and to set the PaymasterId's value to the address of the smart contract. 
By doing this, the extcodesize(account) value will be 0. 
As such, the isContract() will return false to the depositFor() function and will allow the attacker to bypass the check with a smart contract address.


## Recommended Mitigation Steps
Do not trust the result of the extcodesize(account) check, because it can be bypassed easily by using the constructor of a smart contract.
IEntryPoint is used in SmartAccount contract but not imported
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#L59


# Vulnerability details

## Impact
This can potentially break the code of a lot of the functions associated with it in the smartAccount contract.

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

## Tools Used
Manual

## Recommended Mitigation Steps
import contracts/smart-contract-wallet/aa-4337/interfaces/IEntryPoint.sol
THE DOMAINSEPERATOR CANNOT BE RECALCULATED AFTER A HARD FORK HAPPENS
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#L42


# Vulnerability details

## Impact

The variable `DOMAIN_SEPARATOR_TYPEHASH` in `SmartAccount.sol` is cached in the contract storage and will not change after the contract is initialized. However, if a hard fork happens after the contract deployment, it would become invalid on one of the forked chains due to the block.chainid has changed.

```solidity
File: SmartAccount.sol

42:       bytes32 internal constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
```
[Link to Code](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L42)

## Recommended Mitigation Steps

Recommend consider using this [implementation](https://github.com/RealityCards/RealityCards-Contracts/commit/0c405d49861df2e1f1bfe53914a392444f98c2ff), which recalculates the domain separator if the current block.chainid is not the cached chain ID.
```execute()``` and its related functions revert for ```msg.value```> 0
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/base/ModuleManager.sol#L61-L73
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460-L463
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L449-L453
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L489-L492


# Vulnerability details

## Impact
```execTransactionFromModule()``` will revert for ```msg.value``` > 0 as it lacks the ```payable``` modifier

## Proof of Concept
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/base/ModuleManager.sol#L61-L73
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460-L463
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L449-L453
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L489-L492

## Tools Used
Manual Review

## Recommended Mitigation Steps
Add ```payable``` modifier
LOW LEVEL CALL RETURNS TRUE IF THE ADDRESS DOESN’T EXIST
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/common/SecuredTokenTransfer.sol#L22
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/MultiSend.sol#L53-L56


# Vulnerability details

As written in the [solidity documentation](https://docs.soliditylang.org/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions), the low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM. Account existence must be checked prior to calling if needed.

## Proof of Concept

The low-level functions call and delegatecall are used in some places in the code and it can be problematic. For example, in the transferToken of the SecuredTokenTransfer contract there is a low level call in order to call the transfer function, but if the given token address doesn’t exist, success will be equal to true and the function will return true and the code execution will be continued like the call was successful.

```solidity
File: common/SecuredTokenTransfer.sol

22:      let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)

```
[Link to Code](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/common/SecuredTokenTransfer.sol#L22)

Similarly in `MultiSend.sol`, if `to` address doesn’t exist, the delegate call or call will return true and the function won’t revert.

```solidity
File: libs/MultiSend.sol

53:      success := call(gas(), to, value, data, dataLength, 0, 0)

56:      success := delegatecall(gas(), to, data, dataLength, 0, 0)

```
[Link to Code](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/MultiSend.sol#L53-L56)

## Recommended Mitigation Steps

Check before any low-level call that the address actually exists, for example before the low level call in the SecuredTokenTransfer function you can check that the address is a contract by checking its code size.

To Learn more Checkout similar Issue Reported [here](https://code4rena.com/reports/2022-04-axelar/#m-01-low-level-call-returns-true-if-the-address-doesnt-exist)
Cross-Chain Signature Replay Attack
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#L77-L90


# Vulnerability details

# Cross-Chain Signature Replay Attack

## Impact
User operations can be replayed on smart accounts accross different chains. This can lead to user's loosing funds or any unexpected behaviour that transaction replay attacks usually lead to.

## Proof of Concept
As specified by the [EIP4337](https://eips.ethereum.org/EIPS/eip-4337) standard `to prevent replay attacks ... the signature should depend on chainid`. In [VerifyingSingletonPaymaster.sol#getHash](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L77-L90) the chainId is missing which means that the same UserOperation can be replayed on a different chain for the same smart contract account if the `verifyingSigner` is the same (and most likely this will be the case).

## Tools Used
Manual review

## Recommended Mitigation Steps
Add the chainId in the calculation of the UserOperation hash in [VerifyingSingletonPaymaster.sol#getHash](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L77-L90)

```
    function getHash(UserOperation calldata userOp)
    public view returns (bytes32) { // @audit change to view
        //can't use userOp.hash(), since it contains also the paymasterAndData itself.
        return keccak256(abi.encode(
                userOp.getSender(),
                userOp.nonce,
                keccak256(userOp.initCode),
                keccak256(userOp.callData),
                userOp.callGasLimit,
                userOp.verificationGasLimit,
                userOp.preVerificationGas,
                userOp.maxFeePerGas,
                userOp.maxPriorityFeePerGas
		block.chainid // @audit add chain id
            ));
    }
```
SmartAccount Inherits from Initializable but the Initializable contract is not imported from openzepplin
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#L27


# Vulnerability details

## Impact
This can lead to unexpected behavior regarding the upgradability of the contract or other aspects.

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

## Tools Used
Manual

## Recommended Mitigation Steps
Consider importing @openzeppelin/contracts/proxy/utils/Initializable.sol in the SmartAccount contract.
Allows malleable `SECP256K1` signatures
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#L107
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/interfaces/IERC1271Wallet.sol#L18
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/interfaces/IERC1271Wallet.sol#L34
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L347-L350


# Vulnerability details

## Impact
It is possible to use compact signatures and this allows malleability of the signature.

## Description

Here, the `ecrecover()` method doesn't check the `s` range and also compact signatures must not be allowed in order to prevent signature malleability.

Homestead ([EIP-2](https://eips.ethereum.org/EIPS/eip-2)) added this limitation, however the precompile remained unaltered. The majority of libraries, including OpenZeppelin, do this check.

Since an order can only be confirmed once and its hash is saved, there doesn't seem to be a serious danger in existing use cases.

**Reference:**

- https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h
- https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3610
- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7201e6707f6631d9499a569f492870ebdd4133cf/contracts/utils/cryptography/ECDSA.sol#L138-L149

**Affected source code:**

- [VerifyingSingletonPaymaster.sol:107](https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L107)

Additionally, the following interfaces are susceptible to being implemented incorrectly:

- [IERC1271Wallet.sol:18](https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/interfaces/IERC1271Wallet.sol#L18)
- [IERC1271Wallet.sol:34](https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/interfaces/IERC1271Wallet.sol#L34)

`ecrecover`:
- [SmartAccount.sol:347-350](https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L347-L350)

## Recommended Mitigation Steps
As Open Zeppelin did, it's better to remove the compact signatures features.
Incorrect Uint Type Might Result In Wrong(Or Loss) Stake Value
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/aa-4337/core/StakeManager.sol#L59-L73


# Vulnerability details

## Impact
With the help of this bug , the stake value stored in the DepositInfo struct can be incorrect . 

## Proof of Concept

1.) Alice wants to stake using addStake function here https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L59-L73
2.) Alice provides a msg.value  , where msg.value > type(uint112).max (msg.value is provided in wei , so this gets more practical as 10^18wei = 1 ether).
3.) Now here , https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L63 stake is calculated and because msg.value >  type(uint112).max (or (info.stake + msg.value) > type(uint112).max) , 
`stake` variable holds a value larger than what a uint112 can hold(does not over flow because this value is > uint256).
4.) At https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L69 , we cast the `stake` variable into a uint112 and as this value was more than a uint112 this will give an incorrect result or even a loss of stake value.


## Tools Used
 Manual Analysis

## Recommended Mitigation Steps:

Use this line instead
uint112 stake = info.stake + msg.value; So that it reverts when a value larger than type(uint112).max is provided.
SmartAccount.sol Inherit from ISignatureValidatorConstants instead of ISignatureValidator 
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#L25


# Vulnerability details

## Impact
Importing the wrong Interface can lead to unexpected behaviors in the protocol.

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

## Tools Used
Manual

## Recommended Mitigation Steps
Consider importing the right interface.
`transferToken` deducts a fixed gas amount
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/common/SecuredTokenTransfer.sol#L22


# Vulnerability details

## Impact
The `transferToken` function might revert due to a fixed gas deduction

## Proof of Concept
Currently, the `transferToken` function deducts 10_000 gas from the remaining gas:

`let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)` 

This call will always revert if 

a) Less than 10000 gas was provided
b) it is used within a function that already consumed a lot of gas where the remaining gas is < 10_000

## Tools Used
VSCode

## Recommended Mitigation Steps
Consider deduction a proRata share of the remaining gas to prevent deducting more gas as remaining.
`executeBatch()` , `handleOps()`, `handleAggregatedOps`, `innerHandleOp()` are susceptible to DOS with block gas limit
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#L468
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L74
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L80
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L100
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L107
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L112
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L128
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L134


# Vulnerability details

`executeBatch()` , `handleOps()`, `handleAggregatedOps`, `innerHandleOp` are external and public functions and they contain the following code:

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

```
File: contracts/smart-contract-wallet/SmartAccount.sol

468: for (uint i = 0; i < dest.length;) {
```

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

```
File: contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol

74: for (uint256 i = 0; i < opslen; i++) {
80: for (uint256 i = 0; i < opslen; i++) {
100: for (uint256 i = 0; i < opasLen; i++) {
107: for (uint256 a = 0; a < opasLen; a++) {
112: for (uint256 i = 0; i < opslen; i++) {
128: for (uint256 a = 0; a < opasLen; a++) {
134: for (uint256 i = 0; i < opslen; i++) {
```

These are unbounded loops, depending on the length of destination and operations.  
If `dest.length`,  `opslen`, `opasLen` are big enough, block gas limit may be hit.

### Proof of Concept
[https://consensys.github.io/smart-contract-best-practices/attacks/denial-of-service/#dos-with-block-gas-limit](https://consensys.github.io/smart-contract-best-practices/attacks/denial-of-service/#dos-with-block-gas-limit)

### Recommended Mitigation Steps

Limit the max number of loop iterations to prevent hitting block gas limit.
Low-level call/delegatecall can fail silently
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/base/Executor.sol#L13-L34


# Vulnerability details

## Impact
`execute` function in `Executor.sol` will return `true` when calling non-existent contracts. As stated in the [solidity docs](https://docs.soliditylang.org/en/v0.8.17/control-structures.html) "The low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM."

```javascript
function execute(
    address to,
    uint256 value,
    bytes memory data,
    Enum.Operation operation,
    uint256 txGas
) internal returns (bool success) { 
    if (operation == Enum.Operation.DelegateCall) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
        }
    } else {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0) 
        }
    }
    // Emit events here..
    if (success) emit ExecutionSuccess(to, value, data, operation, txGas);
    else emit ExecutionFailure(to, value, data, operation, txGas);
}
```

There is no check for contract existence before calling `execute`, nor inside `execute` function. Therefore this function can fail silently.

## Recommended Mitigation Steps
Please consider checking for the account's existence before doing `call`/`executecall`
checkSignatures will revert for all possible contract signatures
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#L314-L343


# Vulnerability details

## Impact
As specified in `SignatureDecoder.sol`, signatures should be 65-bytes long `(bytes32 r, bytes32 s, uint8 v)` ( with no extra padding for the uint8). But the contract signature branch of `checkSignatures` will revert for all possible signatures following this format, as it can be seen from the followinge excerpt from `checkSignatures` function (code comments were removed for better readability).

```javascript
(v, r, s) = signatureSplit(signatures, i);
if(v == 0) {
    _signer = address(uint160(uint256(r))); 
    require(uint256(s) >= uint256(1) * 65, "BSA021"); 
    require(uint256(s) + 32 <= signatures.length, "BSA022"); 
```

There is no solution to the system of equations below, consequently for all signatures these two requirements are mutually exclusive.

$$
\begin{align*}
  s \ge 65 \\
  s + 32 \le 65 \\
\end{align*}
$$

Therefore for all valid 65-bytes contract signatures (v == 0), `checkSignatures` will revert. Making impossible for users to use this kind of signature to authenticate their transactions. These requirements can be fulfilled by adding enough bytes of any value to the end of the signature in order to increase signatures length (e.g for s = 65, 32 extra bytes would have to be added to the signature), but that would make this signature nonconformant with the specification.

## Recommended Mitigation Steps
To make the code work as intended, please consider removing the following `require`.
```diff
diff --git a/SmartAccount.sol.orig b/SmartAccount.sol
index c4f69a8..a8200d9 100644
--- a/SmartAccount.sol.orig
+++ b/SmartAccount.sol
@@ -319,7 +319,6 @@ contract SmartAccount is
             // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                 // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                 // Here we only check that the pointer is not pointing inside the part that is being processed
-                require(uint256(s) >= uint256(1) * 65, "BSA021");
 
                 // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                 require(uint256(s) + 32 <= signatures.length, "BSA022");
```