Root: The contract does not override AccessControl::renounceRole, allowing signers to revoke their own SIGNING_ROLE without updating the multisig's internal signer tracking variables.
Impact: Internal signer bookkeeping (s_signerCount, s_signers, s_isSigner) becomes inconsistent with actual role assignments, leading to incorrect view data and potential governance deadlock.
Normal Behaviour: Signer membership should be managed exclusively through the multisig's administrative flow (grantSigningRole/revokeSigningRole), ensuring that both role assignments and internal signer state remain consistent.
Issue: Since MultiSigTimelock inherits from OpenZeppelin's AccessControl without overriding renounceRole, any signer can call:
This removes the signer's role at the AccessControl level, but does not update the multisig's internal storage variables:
s_signerCount
s_signers
s_isSigner
As a result, the contract maintains two conflicting sources of truth regarding signer membership.
Likelihood: Low-Medium
Any signer can unintentionally or intentionally renounce their role.
No safeguards or warnings exist to prevent this action.
Impact: Medium
View functions such as getSignerCount() and getSigners() return incorrect data.
The contract may believe the maximum signer count has been reached, preventing the owner from adding new signers.
Multiple self-renunciations can lead to governance deadlock with fewer active signers than expected.
The owner may remain unaware unless monitoring AccessControl::RoleRevoked events closely.
Add the following test to test/unit/MultiSigTimelockTest.t.sol
Run the test using
Logs:
Here are the two approaches one can take:
Disable self-renunciation for signers
Override renounceRole to prevent signer self-removal completely. But then no one will be able to renounce roles in case of any malicious hack of their accounts
Route through multisig revocation logic
Force signer self-removal to go through an alternate version of revokeSigningRole, ensuring internal state updates correctly.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.