The governance proposal execution can succeed even when it doesn't meet quorum requirements. This breaks a fundamental governance safety guarantee and could allow minority stakeholders to push through unauthorized changes.
The vulnerability centers around the proposal execution validation in Governance.sol. A proposal can be executed despite having insufficient votes to meet quorum, bypassing core governance checks.
We expects that successful execution requires both majority support (forVotes > againstVotes
) and meeting quorum (forVotes + againstVotes >= quorumRequired
). However, the execute()
function in Governance.sol lacks proper validation of these requirements before proceeding with execution.
The RAAC governance system faces a vulnerability in its proposal execution mechanism. At its core, the protocol aims to democratize real estate investment through on-chain governance, but the current implementation allows proposals to bypass essential quorum requirements.
Think of this like a homeowners' association making decisions without the minimum required attendance. Even if only 5 out of 100 homeowners show up, their votes could change community rules affecting everyone.
The Governance.sol contract's execute()
function transitions proposals through states without properly validating total participation. The quorum check exists in the contract (defaulting to 4% of total voting power), but it's not enforced at the critical moment of execution.
Let's walk through a real scenario: A proposal gets created when the total veRAACToken
voting power is 1,000,000. This means quorum requires 40,000 votes (4%). An attacker waits for a period of low participation, gets 25,000 votes in favor and 5,000 against. Despite having only 30,000 total votes (below quorum), the proposal can still execute because _isProposalSuccessful()
only checks if forVotes > againstVotes
.
execute _isProposalSuccessful()
Imagine changing property management decisions with just 3% voter participation. For a protocol managing real-world assets, governance integrity is paramount. The GaugeController
uses these decisions to direct yield, while the BoostController
applies voting power, both assuming legitimate governance outcomes.
This manifests when an attacker identifies periods of low voter engagement. During these windows, they can push through proposals affecting real estate management, yield distribution, and protocol parameters despite having far below the required 4% quorum (40,000 veRAAC votes when total voting power is 1,000,000).
The state machine in Governance.sol transitions proposals through various stages, but crucially misses quorum validation at the execution checkpoint. When a proposal receives 25,000 votes in favor and 5,000 against (total participation of just 3%), the contract sees a winning majority without enforcing minimum participation requirements.
The _isProposalSuccessful
function already has the correct validation logic in place, but the issue lies in ensuring this validation is properly enforced during proposal state transitions.
The focus is on ensuring this function is called at all critical state transition points in the proposal lifecycle, particularly during the execute()
flow.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.