xanoutas/solidity-security-findings huggingface dataset:
Executor can backdoor the SubAccount safe by registering a new module to execute any transactions and break the invariants of the system
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/TransactionValidator.sol#L181-L198


# Vulnerability details

## Impact

Executor is an account authorized to make module transactions on a subAccount via ExecutorPlugin and the ExecutorPlugin was enabled as module on the subAccount. 
According to the documentation, [subaccount-execution-via-executor-plugin](https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/docs/Architecture.md#subaccount-execution-via-executor-plugin), the executor can make a transaction by calling the function [executeTransaction()](https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/ExecutorPlugin.sol#L68-L77). 
After the execution of the transaction, the ExecutorPlugin calls validatePostExecutorTransaction() function on TransactionValidator. 
But the transactionValidator miss the check if another module is enabled. 
So the executor can register a new module of the SubAccount. By doing so, the attacker can execute any transation via that module like a backdoor, which breaks the security model of Brahma. 


As stated in the documentation the [main invariants](https://github.com/code-423n4/2023-10-brahma#main-invariants) of the system that :
```
Subaccount should always have SafeModerator enabled as guard on it (unless manually changed by Main Console)
Subaccount should always have ConsoleFallbackHandler enabled as the fallback handler on it (unless manually changed by Main Console). 
```
But the backdoor module will break these invariants. 
the new module call execTransactionFromModule to setGuard(address(0)) or setFallbackHandler(address(0)) to break the invariant. The check in SafeModerator will be bypassed.
In this case, the disable guard and the callback is not done by the Main Console. 

After breaking that by disabling the guard, the module can break also the invariant
```
- Main Console Account should always stay as a module enabled on any subaccount it owns (unless manually changed by Main Console)
```
The backdoor call call [disableModule](https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/lib/safe-contracts/contracts/base/ModuleManager.sol#L47-L54) function 
```
function disableModule(address prevModule, address module) public authorized {
        // Validate module address and check that it corresponds to module index.
        require(module != address(0) && module != SENTINEL_MODULES, "GS101");
        require(modules[prevModule] == module, "GS103");
        modules[prevModule] = modules[module];
        modules[module] = address(0);
        emit DisabledModule(module);
    }
```

Let's analyze the flow in detailed as below:

The function validatePostExecutorTransaction() is called in the ExecutorPlugin function executeTransaction. 
[executeTransaction](https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa2
TRUSTED_VALIDATOR will co-sign transactions without checking the policies that the commit implies
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

Console Fallback Handler `isValidSignature`: https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/ConsoleFallbackHandler.sol#L39-L55


# Vulnerability details

## Impact
TRUSTED_VALIDATORs will co-sign transactions that don't comply with its committed policy, validating transactions that shouldn't be executed, leading to multiple problems.
## Proof of Concept
Exploit scenario:
A Console Account is created with the zero policy, so it will be deployed with the Gnosis Fallback Handler. The owners of the Console Account enforce a new policy. Now, when transactions are sent, we will need the Trusted Validator to co-sign transactions in order to check if the policies the commit implies comply. In order to do this, we will need to have the Console Fallback Handler, which will validate the Policy in `isValidSignature`. The problem is that as the Console Account was deployed with the Gnosis Fallback Handler, so the function `isValidSignature` will not check the Policy. This also happens with imported Safes that add a Policy without changing the Fallback Handler.

This problem will result in transactions that don't comply with the Policy being signed by the Trusted Validator due to calling `isValidSignature` in the wrong Fallback Handler. This will lead to transactions that don't comply with the Policy being executed, which will lead to multiple problems. Example: interacting with Uniswap when the Policy doesn't allow it.
## Tools Used
Manual review
## Recommended Mitigation Steps
Whenever a Policy is updated ensure that the Fallback Handler is ConsoleFallbackHandler.sol.


## Assessed type

Invalid Validation
abi.encodePacked() used in signature can lead to hash collision
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/TransactionValidator.sol#L201-L225
https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/TransactionValidator.sol#L227-L246
https://github.com/code-423n4/2023-10-brahma/blob/dd0b41031b199a0aa214e50758943712f9f574a0/contracts/src/core/PolicyValidator.sol#L144-L167


# Vulnerability details

## Impact
Those functions who relies on the constructed signature would be affected by its hash-collision vulnerability 

## Proof of Concept
Here is how it can be constructed twice by the ethereum mempool miner who can view its signature and submit transactions , as long as he is also the authorized address to operate on sub-account 

Here is how the hash collision on abi.encodePacked() happens :

contract HashCollisionTest {

struct Signature {
    bytes safeSignature;
    bytes validatorSignature;
    uint32 validatorSignatureLength;
    uint32 expiryEpoch;
}

function packSignatures(
    bytes memory safeSignature, 
    bytes memory validatorSignature, 
    uint32 expiryEpoch
) public pure returns (bytes memory) {
    uint32 validatorSignatureLength = uint32(validatorSignature.length);
    return abi.encodePacked(safeSignature, validatorSignature, validatorSignatureLength, expiryEpoch);
}
}

As an example , with input 0xabcdef, 0x1212345678, 1628741250 or 0xabcdef12, 0x12345678, 1628741250 , its output is the same . Then a mempool miner with registered address can watch other's submitted signature , and then construct the same with different inputs , which would be still passed by the check . 
 
## Tools Used
Manual 
## Recommended Mitigation Steps
Use abi.encode() instead of abi.encodePacked()


## Assessed type

Access Control
Nonce manipulation to invalidate transactions
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L58
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L131
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L123-L132


# Vulnerability details

## Impact

An attacker could manipulate nonces to replay signatures or invalidate legitimate transactions because there is no access control on writing to the `executorNonce` mapping. 

## Proof of Concept

The main issue [is in the executorNonce mapping declaration](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L58):

```solidity
mapping(address account => mapping(address executor => uint256 nonce)) public executorNonce;
```
`executorNonce` mapping tracks the nonce used in each execution request per executor, per Safe account. This is used to prevent replay attacks on signatures.

However, there is no access control on writing to this mapping. Any contract or external actor can update the nonce for any executor on any Safe by calling:

```solidity
executorNonce[someAccount][someExecutor] = SomeValue;
```

This is a problem because attackers could:

- Increment the nonce to invalidate legitimate transactions using lower nonces
- Reuse old nonces to replay old signatures 

Either of these attacks could lead to fund loss.

## Vulnerability Details

`executorNonce` mapping is used to track an incremental nonce for each execution request initiated by an executor on a given Safe. This is a common pattern to prevent replay attacks - by requiring a unique nonce for each request, old signatures cannot be reused.

However, there is no access control on writing to this mapping. It is public and can be updated by anyone for example with:

```solidity
executorNonce[someAccount][someExecutor] = someValue; 
```

This enables two potential attack vectors:

1. Nonce manipulation to invalidate transactions

- Attacker monitors the chain to see legitimate nonce values in pending transactions. 

- Right before they are executed, the attacker fronts the transactions by incrementing the nonce. 

- This makes the legitimate transactions use old nonces, causing signature validation to fail.

2. Nonce replay to duplicate transactions

- Attacker retrieves old discarded transaction details and signatures. 

- Attacker sets the nonce mapping back to the old nonce value.

- Attacker re-submits the old transaction. It will now pass signature validation and get re-executed.

Either of these attacks could result in loss of funds:

- Stalled transactions could enable an attacker's txs to extract funds first.

- Replayed transactions could allow double spends, draining extra funds.

The genesis is the lack of access control on the nonce storage. By adding
The lack of checks in `ExecutorPlugin` poses significant risks and should be addressed.
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L44-L50
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L140-L142
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L140-L142


# Vulnerability details

## Impact

The executor signature validation allows arbitrary length signatures. This could allow complex execution logic bugs. 

## Proof of Concept

This allows [arbitrary length executor signatures](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L44-L50).

```solidity
struct ExecutionRequest {
  //...
  bytes executorSignature;
} 
```

[`executorSignature` is then passed to the signature validation](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L140-L142) in _validateExecutionRequest without any length checks:

```solidity
!SignatureCheckerLib.isValidSignatureNow(
  execRequest.executor, 
  _transactionDigest,
  execRequest.executorSignature
)
```

> Looking at the analysis of the arbitrary length signature issue in `ExecutorPlugin`

The `ExecutionRequest` struct defines `executorSignature` as a bytes variable without any length restrictions:

```solidity
!struct ExecutionRequest {
  //...
  bytes executorSignature; 
}
```

This allows signatures of any length to be passed in. Later in `_validateExecutionRequest`, the `executorSignature` is passed directly to `SignatureCheckerLib` for validation: https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L140-L142

```solidity
SignatureCheckerLib.isValidSignatureNow(
  execRequest.executor,
  _transactionDigest,
  execRequest.executorSignature  
)
```

No checks are done on the length of `executorSignature`. This opens up the contract to complex execution logic vulnerabilities.

An attacker could construct a long bytes array with malicious code inside it and set it as the signature. When passed to SignatureCheckerLib, this could trigger unintended execution effects like:

- Causing stack/memory overflows due to large input
- Hiding malicious executable code inside the bytes
- Triggering worst-case gas cost inside SignatureCheckerLib
- Causing revert errors or unexpected exceptions

The root problem is that by allowing arbitrary length signatures, the contract must make assumptions about data passed in by users. Instead, a fixed length like `65 bytes` should be enforced for `secp256k1` to limit the execution surface area. 

The impact of this issue is high, as crafting malicious signatures can lead to complex execution-level attacks on the contract logic.

> examples of how arbitrary length signatures can be explo
The `executorNonce` mapping structure introduces a critical cryptographic vulnerability.
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L58
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L131
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L123
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L136


# Vulnerability details

## Impact

The `executorNonce` mapping uses the executor address as the key. This could allow an attacker to brute force/guess the nonce and replay transactions. 

## Proof of Concept

[This is where executor address is used as the key for the executorNonce mapping.](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L58)

```solidity
mapping(address account => mapping(address executor => uint256 nonce)) public executorNonce;
```

The nonce is then incremented on [line 131](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L131):

```solidity 
executorNonce[execRequest.account][execRequest.executor]++
```
Using the executor address as the key for the nonce mapping could allow an attacker to brute force or guess the nonce, and then replay transactions using that nonce.

> This nonce is incremented and used when constructing the EIP712 signature for each execution request:

**[Line 123](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L123)**, **[Line 131](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L131)**, and **[Line 136](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L136)**

```solidity
bytes32 _transactionStructHash = TypeHashHelper._buildTransactionStructHash(
  ...
  nonce: executorNonce[execRequest.account][execRequest.executor]++
)

_transactionDigest = _hashTypedData(_transactionStructHash);
```

The problem is that using the executor's address for the nonce allows an attacker to brute force or guess the nonce, then reuse it to replay transactions. 

For example, the attacker could extract a past valid signed execution request from the blockchain. They could then brute force the nonce used in that request by calling the public `executorNonce` mapping. 

Once they have the nonce, they can create a new malicious execution request, reuse the nonce, and generate a valid signature again. This new request would execute even though the attacker has no authority.

The root cause is that nonces are tied to executor addresses rather than senders. This violates the security principle
No access control on `executeTransaction` allows unauthorized fund withdrawals.
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L68-L77


# Vulnerability details

## Impact

There is no access control on the `executeTransaction` function. Any address can call this and execute a transaction on the safe if they have a valid signature. This could allow an attacker to drain funds from the safe. 

## Proof of Concept

The [executeTransaction function that lacks access control is](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/ExecutorPlugin.sol#L68-L77)

```solidity
    function executeTransaction(ExecutionRequest calldata execRequest) external nonReentrant returns (bytes memory) {
        _validateExecutionRequest(execRequest);


        bytes memory txnResult = _executeTxnAsModule(execRequest.account, execRequest.exec);


        TransactionValidator(AddressProviderService._getAuthorizedAddress(_TRANSACTION_VALIDATOR_HASH))
            .validatePostExecutorTransaction(msg.sender, execRequest.account);


        return txnResult;
    }
```

The `executeTransaction` function is the main entry point for anyone to execute transactions on a Gnosis Safe via this contract. It takes an `ExecutionRequest` struct as a parameter which contains the transaction details to execute. 

The issue is this function does not have any access control and is marked external, meaning any address can call it. The only validation done is to check the executor's signature and the policy signature in `_validateExecutionRequest`.

This presents a major security risk as an attacker can construct a properly signed `ExecutionRequest` targeting any Gnosis Safe contract and drain funds from it by calling `executeTransaction`. 

For example, consider Safe A with 100 ETH balance. An attacker can:

1. Get the nonce and generate a valid signature as an "executor" for Safe A, even though not authorized. The `executorRegistry` checks are `bypassable`. 

2. Construct an `ExecutionRequest` to invoke `transfer()` on Safe A sending 100 ETH to the attacker's address.

3. Call `ExecutorPlugin.executeTransaction()` with this `ExecutionRequest`. 

The `_validateExecutionRequest()` will pass as the attacker has a valid signature. The transfer will then get executed on Safe A by the contract via a module transaction.

This will drain all 100 ETH from Safe A to the attacker.

The genesis is that by marking `executeTransaction()` as external and not applying access controls, the contract provides a public interface for anyone to execute transactions on any Gnosis Safe if they are able to generate a valid signature. This violates the authentication and authorization requirements for a privileged action like transaction execution.

The impact of this issue is quite severe as it can lead to theft of funds from Gnosis Safes by bypassing signature-based protections.

> Consider this walkthrough as an example execution flow to
Nonce generation must include threshold to avoid collisions during safe deployments.
Audit: 2023-10-brahma-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L253-L256
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L225
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L225
https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L253-L255


# Vulnerability details

## Impact

The nonce generation uses the owner addresses and a salt, but not the threshold. So the same owners with different thresholds will collide. Should also include threshold.

## Proof of Concept

The nonce generation that does not include the threshold parameter [is in the `_genNonce` function](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L253-L256)

```solidity
function _genNonce(bytes32 _ownersHash, bytes32 _salt) private returns (uint256) {

  return uint256(keccak256(abi.encodePacked(
    _ownersHash, 
    ownerSafeCount[_ownersHash]++, 
    _salt,
    VERSION
  )));

}
```

[Specifically, the _ownersHash](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L225) is generated from the owner addresses

```solidity 
bytes32 ownersHash = keccak256(abi.encode(_owners));
```

But the `threshold` is not included in the `_ownersHash` or `_genNonce`.

This means the same owner addresses will generate the same `_ownersHash`, even if they have different thresholds. 

So, this could lead to collisions in the nonces when deploying safes for the same owners but different thresholds.


> The impact of not including the threshold in the nonce generation in `_genNonce`, which is used to generate a unique nonce for each safe deployment.

The nonce relies on two main values:

1. `_ownersHash` - a hash of the owner addresses

2. `_salt` - a random salt provided by the caller

The problem is [`_ownersHash`](https://github.com/code-423n4/2023-10-brahma/blob/c217699448ffd7ec0253472bf0d156e52d45ca71/contracts/src/core/SafeDeployer.sol#L225) only includes the owner addresses, generated by:

```solidity
bytes32 ownersHash = keccak256(abi.encode(_owners)); 
```

It does NOT include the `threshold` value. 

This means the SAME `_ownersHash` will be produced for the same owners, regardless of the threshold.

For example:

Owners A, B, and C with threshold 1 will produce the same `_ownersHash` as A, B, and C with threshold 2.

Then `_genNonce` uses this along with the salt to generate the nonce:

```solidity
function _genNonce(bytes32 _ownersHash, bytes32 _salt) {
  return uint256(keccak256(abi.encodePacked(_ownersHash, /*...*/))); 
}
```

Since the `_ownersHash` is the same for different thresholds, the nonce will be the same.

This caus