Overview
The veRAACToken contract includes a recordVote function for marking users as having voted on a given proposal:
However -> no access control or validation ensures that the caller is either:
The governance contract, or
The voter themselves, or
Any other authorized entity.
Instead, any address can call recordVote(...) for any voter on any proposalId. This allows a malicious actor to front-run or forcibly “mark” another user as having voted—without that user’s consent.
Malicious Caller Identifies a Target and Proposal:
Suppose user victim has not yet voted on proposalId.
The attacker calls:
Because _hasVotedOnProposal[victim][proposalId] is initially false, the function sets _hasVotedOnProposal[victim][proposalId] to true.
Denial of Actual Vote:
When victim later attempts to cast a real vote (likely through the legitimate governance flow), the contract checks:
Because it is now true, the call reverts with AlreadyVoted().
The victim is thereby blocked from submitting their legitimate vote.
Impact on Governance:
The victim’s voting power is effectively nullified for that proposal.
The attacker, by calling recordVote preemptively, denies victim from casting a proper vote.
This is especially impactful for close votes, or in systems where large amounts of voting power are concentrated.
Governance Disruption: Attackers can systematically eliminate particular users from voting, skewing outcomes.
User Confusion and Frustration: The victim receives an AlreadyVoted() error when trying to vote, despite never having cast a vote.
Add access control or other validation to recordVote. Common approaches include:
Restrict Calls to an Authorized Governance Contract:
Check that msg.sender == voter:
If the design intends for the user themselves to directly call recordVote, you can require:
Handle Voting in an External Governance Contract:
Typically, the veToken contract only provides the means to retrieve a user’s voting power. The governance contract itself tracks who has voted and calls getVotingPower(...) or getPastVotes(...). In that pattern, recordVote(...) may not be needed at all.
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.