Core Contracts

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

Vote power manipulation in `castVote` Function

Summary

The castVote function in the Governance contract uses current voting power instead of historical voting power at proposal creation time, allowing users to manipulate votes through temporary voting power acquisition.

Vulnerability Details

In the castVote function, voting power is checked at the time of voting rather than using a snapshot from when the proposal was created:

function castVote(uint256 proposalId, bool support) external override returns (uint256) {
// ...
uint256 weight = _veToken.getVotingPower(msg.sender);
if (weight == 0) {
revert NoVotingPower(msg.sender, block.number);
}
// ...
}

This creates an attack scenerio where:

  • An attacker can wait for a proposal to be created

  • Acquire voting power (e.g., through borrowing or flash loans)

  • Cast their vote with the temporarily acquired power

  • Release the voting power immediately after

The vote remains valid despite no longer having skin in the game

Impact

Allows vote manipulation through temporary token holdings and could lead to malicious proposals being passed

Tools Used

  • Manual code review

Recommendations

  1. Implement vote power snapshotting:

struct ProposalCore {
// ... existing fields ...
uint256 snapshotBlock;
}
function propose(...) external override returns (uint256) {
// ...
_proposals[proposalId] = ProposalCore({
// ... existing fields ...
snapshotBlock: block.number
});
// ...
}
function castVote(uint256 proposalId, bool support) external override returns (uint256) {
ProposalCore storage proposal = _proposals[proposalId];
// ...
uint256 weight = _veToken.getPastVotingPower(msg.sender, proposal.snapshotBlock);
if (weight == 0) {
revert NoVotingPower(msg.sender, proposal.snapshotBlock);
}
// ...
}

Update the IveRAACToken interface to include:

function getPastVotingPower(address account, uint256 blockNumber) external view returns (uint256);
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Governance.castVote uses current voting power instead of proposal creation snapshot, enabling vote manipulation through token transfers and potential double-voting

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Governance.castVote uses current voting power instead of proposal creation snapshot, enabling vote manipulation through token transfers and potential double-voting

Support

FAQs

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

Give us feedback!