President Elector

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

Voters can DOS the selectPresident function call by making it infinitely gas-costly

[M-01] Voters can DOS the selectPresident function call by making it infinitely gas-costly

Summary

The selectPresident function uses a recursive scheme that is repeated by the number of candidates to choose the final candidate as the president. However, the voting mechanism allows users to vote for up to 10 persons, potentially increasing the number of candidates to 10 * NumberOfVoters in the worst case. This leads to significantly increased gas costs for the function call.

Vulnerability Details

The selectPresident function has several issues that contribute to the vulnerability:

  1. Recursive scheme:
    The function calls itself recursively, potentially leading to deep recursion and high gas costs.

  2. Dynamic candidate population:
    Candidates are dynamically added to s_candidateList based on voter rankings, potentially exceeding the maximum allowed candidates.

  3. Lack of candidate limit check:
    There's no explicit check to ensure the number of candidates doesn't exceed a reasonable limit.

  4. Potential for infinite recursion:
    In extreme cases where all voters vote for the same candidate, the recursive calls could theoretically go on indefinitely.

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]);
// Number of candidates can go higher than max! to 10XNumberOfVoters
}
}
}
// Recursive call to selectPresidentFunction!
address[] memory winnerList = _selectPresidentRecursive(
s_candidateList,
0
);
if (winnerList.length != 1) {
revert RankedChoice__SomethingWentWrong();
}
// Reset the election and set President
s_currentPresident = winnerList[0];
s_candidateList = new address[](0);
s_previousVoteEndTimeStamp = block.timestamp;
s_voteNumber += 1;
}

Impact

The selectPresident function cannot be called efficiently or will cost a lot of gas, especially if the number of voters is increased. This could lead to denial of service (DoS) attacks or significantly higher transaction costs for users.

Tools Used

Manual Review

Recommendations

Implement a maximum candidate limit: Add a constant MAX_CANDIDATES and compare it against s_candidateList.length after populating it. If exceeded, revert the transaction.

uint256 candidateCount = s_candidateList.length;
if (candidateCount > MAX_CANDIDATES) {
revert RankedChoice__TooManyCandidates();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year 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.