Brahma - immeas's results

Brahma Console is a custody and DeFi execution environment.

General Information

Platform: Code4rena

Start Date: 13/10/2023

Pot Size: $31,250 USDC

Total HM: 4

Participants: 51

Period: 7 days

Judge: 0xsomeone

Id: 295

League: ETH

Brahma

Findings Distribution

Researcher Performance

Rank: 10/51

Findings: 1

Award: $197.77

QA:
grade-a

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: immeas

Also found by: Alra, Arz, GREY-HAWK-REACH, alexzoid, radev_sw, rvierdiiev, sorrynotsorry

Labels

bug
grade-a
QA (Quality Assurance)
selected for report
sponsor acknowledged
sufficient quality report
Q-03

Awards

197.7721 USDC - $197.77

External Links

QA Report

Summary

idtitle
L-01Changing address for SafeModerator or ConsoleFallbackHandler will break existing subAccounts
L-02No opt-out of creating a safe without looping over nonces
R-01Confusing that two different methods of determining owner are used
NC-01Misleading natspec
NC-02Wrong bytes in comment
NC-03Unused function

Low

L-01 Changing address for SafeModerator or ConsoleFallbackHandler will break existing subAccounts

During execution of operations on sub accounts, fallback handler and guard are not allowed to change:

TransactionValidator::_checkSubAccountSecurityConfig:

File: contracts/src/core/TransactionValidator.sol

182:        address guard = SafeHelper._getGuard(_subAccount);
183:        address fallbackHandler = SafeHelper._getFallbackHandler(_subAccount);
184:
185:        // Ensure guard has not been disabled
186:        if (guard != AddressProviderService._getAuthorizedAddress(_SAFE_MODERATOR_HASH)) revert InvalidGuard();
187:
188:        // Ensure fallback handler has not been altered
189:        if (fallbackHandler != AddressProviderService._getAuthorizedAddress(_CONSOLE_FALLBACK_HANDLER_HASH)) {
190:            revert InvalidFallbackHandler();
191:        }

Here the guard and fallback handler are verified unchanged to what is defined in the address provider service.

The issue is that if governance changes the implementations of either if these, this check will fail for all existing sub accounts. Since they are created with what was the guard and fallback handler at time of safe creation.

The sub accounts are blocked until the console account updates the guard or fallback handler on the sub account.

Impact

Changing address of either SafeModerator or ConsoleFallbackHandler will break every existing subAccount. It also forces the owning console accounts to upgrade to the new implementations without any opt-in.

Recommendation

Consider storing the values in pre-validation and do the comparison against the stored values in post-validation. That way they are independent of any changes from the protocol.

L-02 No opt-out of creating a safe without looping over nonces

When creating new safes, either subAccounts or main console accounts, a nonce is used to create the salt used by the SafeDeployer:

SafeDeployer::_createSafe and _genNonce:

228:        uint256 nonce = _genNonce(ownersHash, _salt);
229:        do {
230:            try IGnosisProxyFactory(gnosisProxyFactory).createProxyWithNonce(gnosisSafeSingleton, _initializer, nonce)
231:            returns (address _deployedSafe) {
232:                _safe = _deployedSafe;
233:            } catch Error(string memory reason) {
234:                // KEK
235:                if (keccak256(bytes(reason)) != _SAFE_CREATION_FAILURE_REASON) {
236:                    // A safe is already deployed with the same salt, retry with bumped nonce
237:                    revert SafeProxyCreationFailed();
238:                }
239:                emit SafeProxyCreationFailure(gnosisSafeSingleton, nonce, _initializer);
240:                nonce = _genNonce(ownersHash, _salt);
241:            } catch {
242:                revert SafeProxyCreationFailed();
243:            }
244:        } while (_safe == address(0));

...

253:    function _genNonce(bytes32 _ownersHash, bytes32 _salt) private returns (uint256) {
254:        return uint256(keccak256(abi.encodePacked(_ownersHash, ownerSafeCount[_ownersHash]++, _salt, VERSION)));
255:    }

If the wallet creation fails, it retries with a new nonce (and thus a new salt) until it succeeds. This opens up an unlikely but possible attack vector where a rich malevolent actor could front run wallet creation by creating a lot of wallets increasing the gas cost for the victim due to the iterations.

This of course costs even more gas for the attacker as they need to actually create the wallets making this attack unlikely. But still possible.

Since the wallets created by the attacker would be identical, a front run here doesn't really do anything else than what the victim wanted, creating a wallet. Hence the wallet created by a possible attacker would work just as well for the victim.

Recommendation

Consider adding a boolean flag if the user wish to iterate over nonces when creating a safe. That way a user can opt-in to having the looping logic or not.

Recommendations

R-01 Confusing that two different methods of determining owner are used

ExecutorRegistry::registerExecutor and deRegisterExecutor uses two different methods of determining if msg.sender is the owner of the subAccount:

File: contracts/src/core/registries/ExecutorRegistry.sol

40:        if (!_walletRegistry.isOwner(msg.sender, _subAccount)) revert NotOwnerWallet();

55:        if (_walletRegistry.subAccountToWallet(_subAccount) != msg.sender) revert NotOwnerWallet();

WalletRegistry::isOwner simply does the same check, subAccountToWallet[_subAccount] == _wallet.

Using two different methods is confusing.

Recommendation

Consider usinng the same method in both calls.

Informational / Non-critical

NC-01 Misleading natspec

WalletRegistry::registerWallet:

File: contracts/src/core/registries/WalletRegistry.sol

31:    /**
32:     * @notice Registers a wallet
33:     * @dev Can only be called by safe deployer or the wallet itself
34:     */

Can only be called by safe deployer or the wallet itself

It cannot be called by safe deployer as it only instructs the wallet to call it on setup (as it only registers msg.sender it would then be the safe deployer address registered as a wallet).

NC-02 Wrong bytes in comment

while declaring SafeHelper._FALLBACK_REMOVAL_CALLDATA_HASH:

File: contracts/src/libraries/SafeHelper.sol

44:     * abi.encodeCall(IGnosisSafe.setFallbackHandler, (address(0))) = 0xf08a0323000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

this is not correct, abi.encodeCall(IGnosisSafe.setFallbackHandler, (address(0))) is in fact:

0xf08a03230000000000000000000000000000000000000000000000000000000000000000

The hash is however calculated on the correct bytes.

NC-03 Unused function

AddressProviderService::_onlyGov is not used anywhere in the code.

Consider removing it as having unused functions can cause confusion and is generally considered bad practice.

#0 - c4-pre-sort

2023-10-22T21:45:31Z

raymondfam marked the issue as sufficient quality report

#1 - alex-ppg

2023-10-27T12:00:58Z

Decent report with well-elaborated findings. L-01 may be a design decision (i.e. a critical update is needed due to a vulnerability and thus SubAccount implementations are forced to update).

#2 - c4-judge

2023-10-27T12:01:12Z

alex-ppg marked the issue as grade-a

#3 - 0xad1onchain

2023-10-27T23:32:11Z

Thanks for the report. I agree with all Non Critical findings L-01: SafeModerator and ConsoleFallbackHandler can only be updated by governance and maybe done in extreme scenarios. Only registries are kept immutable because they hold state L-02: While I totally understand your point that attacker deployed the same bytecode at the deterministic CREATE2 address, for some reason safe changed their safe deployer implementation and removed the initializer as a part of address determination, leading us to question if there is a possible exploit we chose to keep it safe and make sure we use an address that we deploy

#4 - c4-sponsor

2023-10-27T23:32:20Z

0xad1onchain (sponsor) acknowledged

#5 - c4-judge

2023-10-31T21:31:00Z

alex-ppg marked the issue as selected for report

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter