President Elector

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

selectPresident Function Leads to Stack Overflow and Gas Exhaustion in Large-Scale Elections

Summary

The RankedChoice contract suffers from a vulnerability in the selectPresident function that uses a recursive approach to determine the winner of the election. The recursive implementation can lead to stack overflow or out-of-gas issues when dealing with a large number of voters or candidates. This could result in the function failing unexpectedly during execution, preventing the election process from completing successfully.

Vulnerability Details

The selectPresident function relies on the _selectPresidentRecursive helper function to recursively narrow down candidates until a winner is selected. However, with a large number of voters and rounds, this recursive approach can lead to:

  1. Stack Overflow: Recursion depth can exceed the allowed stack size in Solidity, leading to a stack overflow error.

  2. Out-of-Gas Errors: Since each recursive call consumes gas, the function may run out of gas before it can complete, especially in scenarios with many voters or rounds.

The test testSelectPresidentRecursiveFuzz confirmed this behavior, with the function failing due to an array out-of-bounds access, which was likely triggered by exceeding recursion depth limits.

Test:

function testSelectPresidentRecursiveFuzz(uint256 numVoters) public {
numVoters = bound(numVoters, 1, 1000);
orderedCandidates1 = [candidates[0], candidates[1], candidates[2]];
orderedCandidates2 = [candidates[3], candidates[1], candidates[4]];
orderedCandidates3 = [candidates[5], candidates[6], candidates[7]];
uint256 halfVoters = numVoters / 2;
uint256 quarterVoters = numVoters / 3;
for (uint256 i = 0; i < halfVoters; i++) {
vm.prank(voters[i]);
rankedChoice.rankCandidates(orderedCandidates1);
}
for (uint256 i = halfVoters; i < numVoters; i++) {
vm.prank(voters[i]);
rankedChoice.rankCandidates(orderedCandidates2);
}
for (uint256 i = quarterVoters; i < numVoters; i++) {
vm.prank(voters[i]);
rankedChoice.rankCandidates(orderedCandidates3);
}
vm.warp(block.timestamp + rankedChoice.getDuration());
rankedChoice.selectPresident();
address expectedPresident = candidates[0];
assertEq(rankedChoice.getCurrentPresident(), expectedPresident);
}

Impact

The contract may fail to select a winner when there are a large number of voters or candidates, causing the election process to halt and preventing any candidate from being selected as the president.

Tools Used

Manual Review
Foundry Test

Recommendations

Use different approach to achieve the goals

Updates

Lead Judging Commences

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

A high number of candidates could cause an OOG

Support

FAQs

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