Closed c4-submissions closed 10 months ago
raymondfam marked the issue as sufficient quality report
raymondfam marked the issue as primary issue
Invalid
The POC is incorrect as a safe was deployed with null policy by using bytes32(0)
and thus did not have any guard on handler set on it
// 1. deployed with threshold of one for easier testing
address wallet = safeDeployer.deployConsoleAccount(owners, 1, bytes32(0), keccak256("salt"));
Which means user did not set any policy on their main console account and choose to do whatever they want without any validation from trusted validator. In that case they can choose to brick their safe by activating random guards in a 1000 different ways. This issue is more for Gnosis Safe to handle and not us since any safe user irrespective of console user can use such transactions to brick their gnosis safe
0xad1onchain (sponsor) disputed
As the Sponsor correctly states, the Warden describes an issue that may arise in the Gnosis Safe implementation directly. Additionally, the Warden assumes that the signatories of the Gnosis Safe collude in a majority; such attacks are out-of-scope.
alex-ppg marked the issue as unsatisfactory: Out of scope
Lines of code
https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/lib/safe-contracts/contracts/GnosisSafe.sol#L111-L194 https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/lib/safe-contracts/contracts/base/GuardManager.sol#L34-L41 https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/core/TransactionValidator.sol#L64-L107
Vulnerability details
Impact
User funds can be permanently frozen, all normal
Safe
calls will revert if a broken guard is setDescription
Safe
with threshold of one or multiple signers can collude to setup a guard contract that reverts and causes denial of service. If the guardcheck
functions revert, all normalSafe
calls (execTransaction()
) will fail. Even though modules can still execute operations viaexecTransactionFromModule()
because the guard setupGuardManager
-setGuard()
is protected byauthorized
it can only be called byexecTransaction()
so the guard can't be reset and the safe will be completely bricked if a module doesn't have full access to execute any transaction on theSafe
.lib/safe-contracts/contracts/GnosisSafe.sol
-execTransaction()
SubAccount
is safer as long asConsole
is not disabled as amodule
, it could rescue funds and still operate, note that normal calls will still permanently revert andGuard
can't be reset.Console
on the other hand doesn't have amodule
to do any rescue operations and it will be permanently bricked without any way to recover funds.Broken invariants
The sponsor stated 5 main invariants, two of them will be broken if a reverting guard were to be set since no transactions can be executed:
Proof of Concept
test/branch-trees/SafeDeployer/deploy-console-account
and create a new filed namedRevertGuard.sol
-> copy paste the contract:import {Guard} from "safe-contracts/base/GuardManager.sol"; import "safe-contracts/common/Enum.sol";
contract RevertGuard is Guard { function checkTransaction( address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver, bytes memory signatures, address msgSender ) external override { string memory hello = "Your safe is bricked forever"; revert(hello); }
}
executeSafeTxHelper
helper function that can expect revert) inSafeDeployer_DeployConsoleAccountTest
contractrun
make test_func P=testDeployConsoleAccount_DosGuard_0xfuje
Recommended Mitigation
Consider restricting
Console
andSubAccount
to disallow any possible arbitrary guard setting. Consider theguard
atConsole
initialization (SafeModeratorOverridable
) to always check if theguard
address is not changed, enforce it viaTransactionValidator.sol
-validatePostTransactionOverridable()
post transaction check.Assessed type
DoS