Core Contracts

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

Proposal Replay Attack in Governance.sol propose function

Summary

The proposal replay attack vulnerability arises because the contract does not check for duplicate proposals. This allows an attacker to repeatedly submit the same proposal, which could lead to network spam, governance inefficiencies, and potential denial-of-service (DoS) attacks.

Vulnerability Details

function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description,
ProposalType proposalType
) external override returns (uint256) {
uint256 proposerVotes = _veToken.getVotingPower(msg.sender);
if (proposerVotes < proposalThreshold) {
revert InsufficientProposerVotes(msg.sender, proposerVotes, proposalThreshold, "Below threshold");
}
if (targets.length == 0 || targets.length != values.length || targets.length != calldatas.length) {
revert InvalidProposalLength(targets.length, values.length, calldatas.length);
}
>> uint256 proposalId = _proposalCount++; // proposal replay attacks, keep on spamming with same proposals
uint256 startTime = block.timestamp + votingDelay;
uint256 endTime = startTime + votingPeriod;
_proposals[proposalId] = ProposalCore({
id: proposalId,
proposer: msg.sender,
proposalType: proposalType,
startTime: startTime,
endTime: endTime,
executed: false,
canceled: false,
descriptionHash: keccak256(bytes(description)),
targets: targets,
values: values,
calldatas: calldatas
});
// Store the proposal data separately
_proposalData[proposalId] = ProposalData(targets, values, calldatas, description);
emit ProposalCreated(proposalId, msg.sender, targets, values, calldatas, description, proposalType, startTime, endTime, proposerVotes);
return proposalId;
}

The contract does not maintain a record of past proposal hashes to prevent duplicate proposals.

  • The proposalId is incremented sequentially (uint256 proposalId = _proposalCount++), meaning identical proposals will always be accepted with different IDs.

  • An attacker can continuously submit the same proposal, congesting the governance system and spamming voters with redundant proposals.

  • If the contract has limits on active proposals or voting resources, it could prevent legitimate proposals from being processed.

Impact

  • Governance Spam: The system could be flooded with identical proposals, overwhelming voters and making governance less effective.

  • Denial-of-Service (DoS): Attackers could exploit gas or storage limits to prevent the submission of legitimate proposals.

  • Vote Dilution: If resources for proposal processing are limited, it may prevent other users from submitting meaningful proposals.

Tools Used

Manual Review

Recommendations

Enforce Proposal Uniqueness: Store a mapping of keccak256(abi.encode(targets, values, calldatas, description)) to prevent duplicate proposals.

Updates

Lead Judging Commences

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

Governance generates non-unique timelock operation IDs for different proposals with identical parameters, allowing timelock bypass and proposal DoS attacks

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

Governance generates non-unique timelock operation IDs for different proposals with identical parameters, allowing timelock bypass and proposal DoS attacks

Support

FAQs

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