President Elector

First Flight #24
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

Gas Limit DoS via large amount of VOTERS

Summary

The RankedChoice.sol contract contains a vulnerability that can lead to a Denial of Service (DoS) attack. This issue arises from the inefficient handling of claimants in the selectPresident function, where iterating over a large number of voters can cause the transaction to run out of gas, thereby preventing the contract from executing as intended.

Vulnerability Details

Affected code - https://github.com/Cyfrin/2024-09-president-elector/blob/fccb8e2b6a32404b4664fa001faa334f258b4947/src/RankedChoice.sol#L60C5-L93C6

The vulnerability is located in the selectPresident function , specifically at the loop iterating over the voters array:

function selectPresident() external {
if (
block.timestamp - s_previousVoteEndTimeStamp <=
i_presidentalDuration
) {
revert RankedChoice__NotTimeToVote();
}
@> for (uint256 i = 0; i < VOTERS.length; i++) {
address[] memory orderedCandidates = s_rankings[VOTERS[i]][
s_voteNumber
];
for (uint256 j = 0; j < orderedCandidates.length; j++) {
if (!_isInArray(s_candidateList, orderedCandidates[j])) {
s_candidateList.push(orderedCandidates[j]);
}
}
}
……
}

The selectPresident function is designed to select the president according the candidates’ rank. However, if the number of voters is extremly large, the loop iterating over the voters array can consume a significant amount of gas. This can lead to a situation where the transaction exceeds the gas limit and fails, effectively making it impossible to close the pot and distribute the rewards.

Exploit

  1. initiates a big RankedChoice with a lot of voters

  2. every voter rank the candidates

  3. when someone call the selectPresident that will be very costly

function testGasCostForSelectPresidentWithManyVoters() public {
uint256 VOTERNUMBER = 1000;
address[] memory testVoters = new address[]();
for (uint256 i = 0; i < VOTERNUMBER; i++) {
testVoters[i] = address(uint160(i));
}
RankedChoice rankedChoice2 = new RankedChoice(testVoters);
orderedCandidates = [candidates[0], candidates[1], candidates[2]];
for (uint256 i = 0; i < VOTERNUMBER; i++) {
vm.startPrank(testVoters[i]);
rankedChoice2.rankCandidates(orderedCandidates);
vm.stopPrank();
}
vm.warp(block.timestamp + rankedChoice.getDuration());
uint256 gasBeforeClose = gasleft();
rankedChoice2.selectPresident();
uint256 gasUsedClose = gasBeforeClose - gasleft();
console.log("Gas used for select president with 2000 voters:", gasUsedClose);
}
"Gas used for select president with 2000 voters:", 11519040

Impact

The primary impact of this vulnerability is a Denial of Service (DoS) attack vector.

Tools Used

Manual Review and Forge Tests

Recommendations

Size Control:Limit the size of the voter list during contract deployment.

Gas Optimization: Optimize the loop to reduce gas consumption by using a local variable to itterate over, like in the following example:

- for (uint256 i = 0; i < VOTERS.length; i++) {
- address[] memory orderedCandidates = s_rankings[VOTERS[i]][
- s_voteNumber
- ];
- for (uint256 j = 0; j < orderedCandidates.length; j++) {
- if (!_isInArray(s_candidateList, orderedCandidates[j])) {
- s_candidateList.push(orderedCandidates[j]);
- }
- }
- }
+ uint256 voters_length = voters.length;
+ for (uint256 i = 0; i < voters_length; i++) {
+ address[] memory orderedCandidates = s_rankings[VOTERS[i]][
+ s_voteNumber
+ ];
+ for (uint256 j = 0; j < orderedCandidates.length; j++) {
+ if (!_isInArray(s_candidateList, orderedCandidates[j])) {
+ s_candidateList.push(orderedCandidates[j]);
+ }
+ }
+ }

Batch Processing: Implement batch processing for distributing rewards. This will redesign the protocol functionallity but instead of processing all claimants in a single transaction, allow the function to process a subset of claimants per transaction. This can be achieved by introducing pagination or limiting the number of claimants processed in one call.

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

[INVALID] A high number of voters can lead to OOG in selecting the president

Support

FAQs

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