xanoutas/solidity-security-findings huggingface dataset:
Denial of Service Vulnerability via Front-running in registerSubAccount Function
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/registries/WalletRegistry.sol#L49-L55


# Vulnerability details

## Impact
The identified vulnerability presents a low to medium-severity risk, where a malicious entity could exploit the front-running vector in the blockchain network to prevent the successful execution of the `registerSubAccount` function. While this doesn't directly compromise funds or account control, it does introduce a potential denial of service (DoS) scenario. Legitimate users might be impeded from adding sub-accounts, causing disruption in user activities and potentially eroding trust in the platform's robustness. This issue becomes increasingly critical if the affected accounts are intended for significant operational or fund management roles, such as multisig wallets or organizational sub-accounts.

## Proof of Concept
The vulnerability exists due to the nature of transaction execution and state mutability on the Ethereum blockchain, specifically targeting the registerSubAccount function.

1. Given the code in the `registerSubAccount` function, a legitimate user attempts to register a sub-account. This transaction is broadcast to the network and enters the mempool, awaiting confirmation. 

2. A malicious actor, observing transactions in the mempool, issues a transaction with a higher gas fee, which calls a function modifying the state required by `registerSubAccount` or filling up the sub-account slots, thereby denying the legitimate transaction.

3. The malicious transaction is processed first due to its higher gas fee, altering the contract state and causing the legitimate `registerSubAccount` transaction to fail when it's subsequently processed.

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/registries/WalletRegistry.sol#L51

```solidity
        if (subAccountToWallet[_subAccount] != address(0)) revert AlreadyRegistered();
```
This scenario is predicated on the ability of attackers to view and react to pending transactions in the mempool and the state-dependent nature of the `registerSubAccount` function.

## Tools Used
Manual

## Recommended Mitigation Steps
To protect against this type of vulnerability, several strategies could be employed:

1. **Queueing Mechanism**: Implement a mechanism that allows users to submit requests that are processed in order, rather than based on transaction ordering on the blockchain. This could be a contract that queues requests and processes them in batches.

2. **Off-chain Approvals**: Require users to obtain some form of off-chain approval or token before they can call `registerSubAccount`. This could involve off-chain systems that provide users with signed messages or tokens that they can then submit to the blockchain to prove that they have permission to register the sub-account.


## Assessed type

Other
A safe that been created using version 1.40=< will not be compatible with Brahma
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/SafeModeratorOverridable.sol#L16


# Vulnerability details

### Impact
Safe's created outside of the Brahma ecosystem should be able to seamlessly integrate into the `Brahma`. This Safe should call `WalletRegistry.registerWallet` to register. After registration, 
this safe will be a `consoleAccount`  and should be able to use the same functionality that all the other `consoleAccounts` have.

However, Safe's that have been created using version 1.4.0=< are not fully compatible with Brahma. This is because, in version 1.4.0, `IERC165` support has been [added](https://github.com/safe-global/safe-contracts/pull/310/files) to the `GuardManager.sol`, this is the code added:
```diff
+ if (guard != address(0)) {
+ require(Guard(guard).supportsInterface(type(Guard).interfaceId), "GS300");
+ }
```

This means that every Safe that has been created using Safe's contract version 1.40 and up, can only add guards that support the `EIP-165` interface, as read from the [CHANGELOG.md](https://github.com/safe-global/safe-contracts/blob/main/CHANGELOG.md?plain=1#L206)
### Proof of Concept
Consider the following:
- Alice has a safe setup.
- Alice wants to integrate her safe into the Brahma ecosystem.
- Alice calls `WalletRegistry.registerWallet`, this call succeeds.
- Alice decides she want to implement the guard contract provided by the Brahma ecosystem, `SafeModeratorOverridable.sol`
- Alice calls `GnosisSafe.setGuard(address(SafeModeratorOverridable))`
- This will fail because of this new require statement in Safe contracts v1.4.0=< :
```javascript
function setGuard(address guard) external authorized {
        if (guard != address(0)) {
            require(Guard(guard).supportsInterface(type(Guard).interfaceId), "GS300");
        }
```
because the `SafeModeratorOverridable.sol` does not support the `EIP-165` interface:
```javascript
source: contracts/src/core/SafeModeratorOverridable.sol

contract SafeModeratorOverridable is AddressProviderService, IGuard {
```

This means that every Safe created with version 1.4.0 or up, can not implement the guard contract, which is a fundamental part of the way the ConsoleAccounts function.
### Tools Used
Manual Review
## Recommended Mitigation Steps
Add support for the `EIP-165` interface or update the Safe contracts used in Brahma from 1.3.0 to the most recent version.


## Assessed type

Context
Operators cannot be removed by the Console Account if Needed
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/lib/safe-contracts/contracts/base/OwnerManager.sol#L70-L87


# Vulnerability details

## Impact
An operator is essentially an owner of a sub-account, Talking about the context of a Gnosis safe account, cause sub-accounts are basically Gnosis accounts too, but in the context in which Brahma is using them as a sub-account, they still actually function, the same way a gnosis safe functions, only the policy commit setup by the Owner console Account are what determines what transactions to be performed by the sub-accounts. This can also lead to some unwanted actions that the Brahma team would want to implement, but are unable to, like the operators being removed, since the operators are owners and removing the owners of a gnosis safe requires a safe transaction, a safe transaction requires signatures from the defined thresholds if other operators do not put their signatures or sign the transactions, then an operator has no way to get removed. 

This can lead to some problems if the operators turn inactive or malicious as they are not included in the list of trusted actors in the protocol.

## Proof of Concept
```solidity
/// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
    ///      This can only be done via a Safe transaction.
    /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
    /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
    /// @param owner Owner address to be removed.
    /// @param _threshold New threshold.
    function removeOwner(
        address prevOwner,
        address owner,
        uint256 _threshold
    ) public authorized {
        // Only allow to remove an owner, if threshold can still be reached.
        require(ownerCount - 1 >= _threshold, "GS201");
        // Validate owner address and check that it corresponds to owner index.
        require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
        require(owners[prevOwner] == owner, "GS205");
        owners[prevOwner] = owners[owner];
        owners[owner] = address(0);
        ownerCount--;
        emit RemovedOwner(owner);
        // Change threshold if threshold was changed.
        if (threshold != _threshold) changeThreshold(_threshold);
    }
```

This code in the Owner Manager of the Gnosis safe clearly states the requirements to remove an owner of a safe, since operators act as safe owners in the context of the Gnosis safe the Console Account, having any need to get rid of the operator could face potential roadblocks if other Operators in the owners list also are not active or also turn malicious, or even worse the operator might be the only operator currently for that sub Account.

## Tools Used
Manual Review

## Recommended Mitigation Steps
This is an implementation issue colliding with how the Gnosis Safe implem
_data.length is not being checked against _signature.length in 'isValidSignature', which can lead to unexpected behavior
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/ConsoleFallbackHandler.sol#L39-L55


# Vulnerability details

### Impact
In `ConsoleFallbackHandler.isValidSignature`, `bytes memory _data` and `bytes memory _signature` are being used to validate the signature of the callers. This function makes a call to `GnosisSafe.checkSignatures`.
```javascript
source: contracts/lib/safe-contracts/contracts/handler

function isValidSignature(bytes calldata _data, bytes calldata _signature) public view override returns (bytes4) {
//.. ommitted code
@>            safe.checkSignatures(messageHash, _data, _signature);
//.. ommitted code
    }
```

However, nowhere in the `isValidSignature` is `_data.length` checked against `_signature.length`. This can lead to unexpected behaviour. 

The Safe team has fixed this bug in [V1.4.0](https://github.com/safe-global/safe-contracts/blob/main/CHANGELOG.md?plain=1#L190). This is the [PR](https://github.com/safe-global/safe-contracts/pull/500). Unfortunately, Brahma uses Safe V1.3.0, which does not include this fix.
### Tools Used
Manual Review
## Recommended Mitigation Steps
Use an updated version of Safe.





## Assessed type

Invalid Validation
`ExecutorPlugin` is not enabled as module, when `subaccounts` are created.
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/SafeDeployer.sol#L168-L205


# Vulnerability details

According to the Contest Overview,
* Executor - An account authorized to make module transactions on a subAccount via `ExecutorPlugin`, ExecutorPlugin `needs` to be enabled as `module` on `subAccount`.

  For `ExecutorPlugin` to make module transactions, it needs to be enabled as a module on the subaccount.
  During subaccount creation, `_setupSubAccount()` sets the fallback handler and guard on the subaccount, but fails to set the `ExecutorPlugin` as module.
  ```solidity
      function _setupSubAccount(address[] memory _owners, uint256 _threshold, address _consoleAccount)
        private
        view
        returns (bytes memory)
    {
        address safeEnabler = AddressProviderService._getAuthorizedAddress(_SAFE_ENABLER_HASH);
        Types.Executable[] memory txns = new Types.Executable[](2);


        // Enable Brhma Console account as module on sub Account
        txns[0] = Types.Executable({
            callType: Types.CallType.DELEGATECALL,
            target: safeEnabler,
            value: 0,
            data: abi.encodeCall(IGnosisSafe.enableModule, (_consoleAccount))
        });


        // Enable guard on subAccount
        txns[1] = Types.Executable({
            callType: Types.CallType.DELEGATECALL,
            target: safeEnabler,
            value: 0,
            data: abi.encodeCall(IGnosisSafe.setGuard, (AddressProviderService._getAuthorizedAddress(_SAFE_MODERATOR_HASH)))
        });


        return abi.encodeCall(
            IGnosisSafe.setup,
            (
                _owners,
                _threshold,
                AddressProviderService._getAuthorizedAddress(_GNOSIS_MULTI_SEND_HASH),
                abi.encodeCall(IGnosisMultiSend.multiSend, (SafeHelper._packMultisendTxns(txns))),
                AddressProviderService._getAuthorizedAddress(_CONSOLE_FALLBACK_HANDLER_HASH),
                address(0),
                0,
                address(0)
            )
        );
    }
  ```

## Impact
This leads to a situation where subaccounts are created but lack `ExecutorPlugin` set as a module, this prevents `executors` from executing transactions as a module.


## Tools Used
Manual Review

## Recommended Mitigation Steps
A call to set `ExecutorPlugin` as a module should be added to the `_setupSubAccount()` function to ensure that every new subaccount has `ExecutorPlugin` enabled. 



## Assessed type

Access Control
calling EnumerableSet Function can lead to Out-of-Gas error 
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/registries/ExecutorRegistry.sol#L75


# Vulnerability details

## Impact
The values() function when called within the getExecutorsForSubAccount function can contribute to the gas shortage.

The values function is part of the ```EnumerableSet.sol``` library from OpenZeppelin. It retrieves all the values in the set and returns them in an array.
The values function in  involves iterating over the set and populates an array from storage, which requires higher computational operation as indicated in the contract and thus can lead to out of gas error.

## Proof of Concept
The values() function is view but it is inherited in the ```ExecutorRegistry.sol``` contract and called internally by ``` getExecutorsForSubAccount``` which will cost gas.

```
/**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }
```
OpenZeppelin clearly warn about using of ```values``` function of ```EnumerableSet.sol``` contract as it can lead to shortage of gas.

## Tools Used
Manual Review

## Recommended Mitigation Steps
The first recommendation is made in area of limiting number of iteration in the function to avoid out of gas error.
The second is made in area of modifying the ```set``` params pointer for ```values``` function from storage to calldata so that it is not stored and just called when function executes.

```diff
- function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
+ function values(Bytes32Set calldata set) internal view returns (bytes32[] memory) {

- bytes32[] memory store = _values(set._inner);
+ bytes32[] calldata store = _values(set._inner);

- bytes32[] memory result;
+ bytes32[] calldata result;
 ```



## Assessed type

Other
Eth can get stuck in ConsoleFallbackHandler.sol
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/ConsoleFallbackHandler.sol#L41


# Vulnerability details

## Impact
Payable allows a user to send ether to contract but no means to withdraw it.
If ethers is send to the contract it will be stuck as there is no means to withdraw it.

## Proof of Concept
The payable address allows for sending message to the contract.
```
GnosisSafe safe = GnosisSafe(payable(msg.sender));
```
## Tools Used
Manual code review

## Recommended Mitigation Steps

Remove payable so that ether cannot be send to the contract.
```diff
-	GnosisSafe safe = GnosisSafe(payable(msg.sender));
+	GnosisSafe safe = GnosisSafe(msg.sender);
```



## Assessed type

Payable
Wallet should be registered
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/registries/WalletRegistry.sol#L49-L55


# Vulnerability details

## Impact
In WalletRegistry.sol, the registerSubAccount() method should check if _wallet param is registered otherwise revert. All sub accounts are to have a registered console accounts/wallets

## Proof of Concept
In the code below, it shows a subaccount can be registered with a non-existing wallet which may cause the protocol to behave differently
```sol
function registerSubAccount(address _wallet, address _subAccount) external {
        if (msg.sender != AddressProviderService._getAuthorizedAddress(_SAFE_DEPLOYER_HASH)) revert InvalidSender();
        if (subAccountToWallet[_subAccount] != address(0)) revert AlreadyRegistered();
        subAccountToWallet[_subAccount] = _wallet;
        walletToSubAccountList[_wallet].push(_subAccount);
        emit RegisterSubAccount(_wallet, _subAccount);
    }
```

## Tools Used
Manual review
## Recommended Mitigation Steps
The following can be added to check for registeration of wallet
```
 if (!isWallet[_wallet]) revert NotRegistered();
```


## Assessed type

Invalid Validation
manipulate the contract's state
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b410/contracts/src/core/SafeDeployer.sol#L230-L243


# Vulnerability details

## Impact
This vulnerability allows an attacker to repeatedly call a function within the smart contract before the previous call completes, which can lead to unexpected behavior and potentially allow the attacker to manipulate the contract's state.

## Proof of Concept
To exploit this vulnerability, an attacker would need to trigger the _createSafe function and repeatedly call it before the previous execution completes. Here is a Proof of Concept (PoC) code that demonstrates how the vulnerability could be exploited:

Attacker deploys a malicious contract with the following code:
contract MaliciousContract {
    address vulnerableContract;
    
    function setVulnerableContract(address _vulnerableContract) public {
        vulnerableContract = _vulnerableContract;
    }
    
    function exploit() public {
        // Call the vulnerable function repeatedly
        for (uint i = 0; i < 10; i++) {
            VulnerableContract(vulnerableContract)._createSafe([msg.sender], "", 0x0);
        }
    }
    
    function() external payable {
        // Revert the call to prevent ETH transfer
        revert();
    }
}

contract VulnerableContract {
    function _createSafe(address[] calldata _owners, bytes memory _initializer, bytes32 _salt) internal returns (address _safe);
}
Attacker deploys an instance of the MaliciousContract and sets the address of the vulnerable contract using the setVulnerableContract function.

Attacker calls the exploit function in the MaliciousContract. This will trigger the _createSafe function multiple times before the previous execution completes.

The vulnerable contract will process each _createSafe function call one by one. However, since the attacker is calling it repeatedly, the contract will be in an inconsistent state, as it is unable to complete the execution of each call before the next one is triggered.

This exploit takes advantage of the fact that the _createSafe function does not contain an ETH transfer vulnerability. Instead, it allows the attacker to repeatedly trigger the function and cause unexpected behavior or manipulate the contract's state.

## Tools Used
self-tool
## Recommended Mitigation Steps
A possible fix for this vulnerability is to add a boolean flag to keep track of the current execution state and revert if reentrancy is detected. Here's an example of a patched code:

uint256 nonce = _genNonce(ownersHash, _salt);
bool creationFailed;

do {
    try IGnosisProxyFactory(gnosisProxyFactory).createProxyWithNonce(gnosisSafeSingleton, _initializer, nonce) returns (
        address _deployedSafe
    ) {
        _safe = _deployedSafe;
        creationFailed = false;
    } catch Error(string memory reason) {
        // KEK
        if (keccak256(bytes(reason)) != _SAFE_CREATION_FAILURE_REASON) {
            // A safe is already deployed with the same salt, retr
Protocol doesn't follow the EIP-1271 Standard properly.
Audit: 2023-10-brahma-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/ConsoleFallbackHandler.sol#L39


# Vulnerability details

## Impact
Due to this, the function `isValidSignature` might return unexpected value and never return `ERC1271_MAGIC_VALUE` and always revert `execTransaction` function.

## Proof of Concept
As Per EIP-1271 standard, function `isValidSignature` should be isValidSignature(bytes32,bytes) instead of isValidSignature(bytes,bytes).

Below is the affected area of code:
```solidity
@> function isValidSignature(bytes memory _data, bytes memory _signature) public view override returns (bytes4) {
        // Caller should be a Safe
        GnosisSafe safe = GnosisSafe(payable(msg.sender));
        bytes32 messageHash = getMessageHashForSafe(safe, _data);
        if (_signature.length == 0) {
            require(safe.signedMessages(messageHash) != 0, "Hash not approved");
        } else {
            /// @dev For validating signatures, `PolicyValidator` is invoked to ensure that
            /// the intent of `messageHash` signed by the owners of the safe, complies with its committed
            /// policy
            PolicyValidator policyValidator =
                PolicyValidator(AddressProviderService._getAuthorizedAddress(_POLICY_VALIDATOR_HASH));
            require(policyValidator.isPolicySignatureValid(msg.sender, messageHash, _signature), "Policy not approved");
            safe.checkSignatures(messageHash, _data, _signature);
        }
        return EIP1271_MAGIC_VALUE;
    }
```
Link to EIP-1271 Standard: https://eips.ethereum.org/EIPS/eip-1271
## Tools Used
Manual Review 
## Recommended Mitigation Steps
Follow the EIP-1271 Specifications Properly.


## Assessed type

Other