Core Contracts

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

Weak Salt Generation Grief Attack

Summary

In the Governance.sol contract due to weak salt generation, a malicious actor with significant voting power can front-run and grief the queueing of proposals by copying the proposal targets, values, calldatas, and description, and queueing first.

Vulnerability Details

The vulnerability arises from the weak salt generation in the _queueProposal function. The salt is generated using the descriptionHash of the proposal, which can be easily replicated by a malicious actor. By copying the proposal's targets, values, calldatas, and description, a malicious actor can create an identical proposal and queue it first. This front-running attack can prevent the original proposal from being queued and executed, effectively griefing the governance process.

Impact

A malicious actor with significant voting power can disrupt the governance process by front-running and griefing proposals. This can prevent legitimate proposals from being queued and executed, undermining the integrity and effectiveness of the governance system. It can lead to delays in implementing important decisions and erode trust in the protocol's governance mechanisms.

Tools Used

Manual Review

Recommendations

To mitigate this vulnerability, improve the salt generation mechanism to make it more resistant to front-running attacks. One approach is to include a unique identifier, such as the proposer's address or a nonce, in the salt generation. Here is an example of how to implement this:

function _queueProposal(uint256 proposalId) internal {
ProposalCore storage proposal = _proposals[proposalId];
// Include proposer's address and proposalId in the salt generation
bytes32 salt = keccak256(abi.encode(proposal.descriptionHash, proposal.proposer, proposalId));
bytes32 id = _timelock.hashOperationBatch(
proposal.targets,
proposal.values,
proposal.calldatas,
bytes32(0),
salt
);
// Check if already queued
if (_timelock.isOperationPending(id)) {
revert ProposalAlreadyExecuted(proposalId, block.timestamp);
}
// Schedule in timelock
_timelock.scheduleBatch(
proposal.targets,
proposal.values,
proposal.calldatas,
bytes32(0),
salt,
_timelock.getMinDelay()
);
emit ProposalQueued(proposalId, block.timestamp, id);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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 7 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.

Give us feedback!