Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect access control in Governance::cancel function allows unauthorized proposal cancellation

Summary

A logical error in the cancel function's access control check allows any user to cancel governance proposals due to incorrect use of logical AND (&&) instead of OR (||).

Vulnerability Details

In the following function, it uses && (AND) instead of || (OR) in its access control check. This means the function will only revert if both conditions are true:

  1. The caller is not the proposer AND

  2. The proposer's voting power is above threshold

As a result, any external account can cancel a proposal when the proposer still has sufficient voting power, which completely bypasses the intended access control.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/governance/proposals/Governance.sol#L261-L266

Impact

  • Any external account can cancel active governance proposals

  • Potential for governance disruption through mass cancellation of proposals

  • Breaks fundamental access control assumptions

  • Could be used as a denial-of-service vector against the governance process

  • Undermines the reliability of the governance system

Tools Used

Manual code review

Recommendations

Change the logical operator from && to ||:

function cancel(uint256 proposalId) external override {
ProposalCore storage proposal = _proposals[proposalId];
if (proposal.startTime == 0) revert ProposalDoesNotExist(proposalId);
ProposalState currentState = state(proposalId);
if (currentState == ProposalState.Executed) {
revert InvalidProposalState(proposalId, currentState, ProposalState.Active, "Cannot cancel executed proposal");
}
- if (msg.sender != proposal.proposer &&
+ if (msg.sender != proposal.proposer ||
_veToken.getVotingPower(proposal.proposer) >= proposalThreshold) {
revert InsufficientProposerVotes(proposal.proposer,
_veToken.getVotingPower(proposal.proposer),
proposalThreshold,
"Not authorized to cancel");
}
proposal.canceled = true;
emit ProposalCanceled(proposalId, msg.sender, "Proposal canceled by proposer");
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!