A medium-severity issue exists in the proposal execution flow of the Governance contract. When a proposal is in the Succeeded state, the execute function calls _queueProposal(proposalId), which in turn calls _timelock.scheduleBatch(). However, scheduleBatch() is restricted to callers with the PROPOSER_ROLE. Since the execute function is external and does not enforce any access control, any user (who is not the proposer) can trigger this function, causing the call to revert due to insufficient permissions.
When a proposal reaches the Succeeded state, the following execution path is taken:
1. Execution Flow in execute Function:
• The contract checks if the proposal’s current state is Succeeded.
• If so, it calls _queueProposal(proposalId).
2. Inside _queueProposal Function:
• The function computes the required parameters and then calls _timelock.scheduleBatch().
• However, scheduleBatch() includes an access control check and requires the caller to have the PROPOSER_ROLE.
3. Issue:
• Since the execute function is external and lacks an access control modifier, any user can call it.
• If the caller is not the original proposer (i.e., does not have the PROPOSER_ROLE), the call to scheduleBatch() will revert.
• This effectively prevents the proposal from being queued even if it has already succeeded, potentially bricking the proposal.
• Governance Paralysis: Valid proposals may never progress past the Succeeded state if executed by an unauthorized user, disrupting the normal governance process.
• Denial of Service: The inability to queue proposals can lead to a DoS condition where proposals remain stuck, impacting protocol upgrades or critical changes.
• User Confusion: Lack of clear access control in the execution flow can lead to unexpected reverts and erode trust in the governance system.
• Manual code review
• Access Control Adjustment: Modify the execute function or _queueProposal to either enforce that only the proposer (or an authorized account) can queue the proposal, or delegate the queuing process to an account with the PROPOSER_ROLE.
• Role Verification: Consider implementing a role check within the execute function to ensure that if the proposal is in the Succeeded state, the caller possesses the PROPOSER_ROLE before attempting to queue the proposal.
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.