Core Contracts

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

Malicious Proposal Cancellation via Voting Power Manipulation

Summary

The cancel function allows a proposal to be canceled if the proposer's voting power drops below the proposalThreshold. A malicious user can exploit this by:

  1. Acquiring sufficient voting power (e.g., by locking tokens) to propose a governance action.

  2. Immediately removing their tokens (e.g., by unlocking or transferring them) to reduce their voting power below the threshold.

  3. Calling cancel to cancel the proposal they just created.

This behavior can be used to:

  • Disrupt governance by spamming proposals and canceling them.

  • Waste gas and create confusion in the governance process.

  • Manipulate governance outcomes by canceling proposals that are unfavorable to the attacker.

Vulnerability Details

Root Cause:

The vulnerability arises from the following logic in the cancel function:

if (msg.sender != proposal.proposer &&
_veToken.getVotingPower(proposal.proposer) >= proposalThreshold) {
revert InsufficientProposerVotes(proposal.proposer,
_veToken.getVotingPower(proposal.proposer), proposalThreshold, "Proposer lost required voting power");
}
  • The function allows cancellation if the proposer's voting power drops below the threshold, regardless of who calls the function.

  • There is no mechanism to prevent the proposer from intentionally reducing their voting power after creating a proposal.

** Attack Scenario**:

  1. Step 1: A malicious user locks tokens to acquire sufficient voting power (>= proposalThreshold).

  2. Step 2: The user creates a proposal using the propose function.

  3. Step 3: Immediately after creating the proposal, the user unlocks or transfers their tokens, reducing their voting power below the threshold.

  4. Step 4: The user calls the cancel function to cancel the proposal.

  5. Step 5: The proposal is canceled, and the governance process is disrupted.

** Technical Analysis**:

  • The cancel function does not validate whether the proposer intentionally reduced their voting power.

  • The function relies on the proposer's current voting power at the time of cancellation, which can be manipulated.

  • This creates a loophole that allows malicious actors to exploit the governance system.

Impact

  • Governance Disruption: Malicious actors can spam proposals and cancel them, wasting gas and creating confusion.

  • Loss of Trust: Users may lose trust in the governance system if proposals can be canceled arbitrarily.

  • Manipulation: Attackers can cancel proposals that are unfavorable to them, undermining the fairness of the governance process.

Proof of Concept:

  1. A malicious user locks tokens to acquire sufficient voting power (>= proposalThreshold).

  2. The user creates a proposal using the propose function.

  3. Immediately after creating the proposal, the user unlocks or transfers their tokens, reducing their voting power below the threshold.

  4. The user calls the cancel function to cancel the proposal.

  5. The proposal is canceled, and the governance process is disrupted.

Tools Used

Manual Review

Recommendations

Add a Cancellation Delay:

  • Introduce a delay between proposal creation and cancellation to prevent immediate cancellation.

  • Example:

uint256 public constant CANCELLATION_DELAY = 1 days;
function cancel(uint256 proposalId) external override {
ProposalCore storage proposal = _proposals[proposalId];
if (proposal.startTime == 0) revert ProposalDoesNotExist(proposalId);
// Ensure cancellation delay has passed
if (block.timestamp < proposal.startTime + CANCELLATION_DELAY) {
revert CancellationNotAllowed(proposalId, proposal.startTime + CANCELLATION_DELAY, block.timestamp);
}
// Only the proposer can cancel the proposal
if (msg.sender != proposal.proposer) {
revert OnlyProposerCanCancel(proposalId, msg.sender, proposal.proposer);
}
proposal.canceled = true;
emit ProposalCanceled(proposalId, msg.sender, "Proposal canceled by proposer");
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge 4 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.