President Elector

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

Replay Attack and Signature Manipulation

Summary

The RankedChoice contract is vulnerable to replay attacks due to its rankCandidatesBySig function not including mechanisms to prevent the reuse of signatures. This vulnerability allows an attacker to exploit valid signatures from previous transactions to submit multiple votes, potentially altering the election results.

Vulnerability Details

The rankCandidatesBySig function in the RankedChoice contract allows users to submit their ranked list of candidates using a signature. However, the current implementation does not include a mechanism to prevent the reuse of a valid signature. This opens the possibility of a replay attack, where an attacker could reuse a previously valid signature to submit the same vote multiple times.

Impact

An attacker can potentially manipulate the voting process by re-submitting previously signed votes, thereby altering the election outcome. This vulnerability undermines the integrity of the voting process by allowing vote duplication.

Exploit Scenario

  1. A voter signs a ranked list of candidates and submits it via rankCandidatesBySig.

  2. An attacker intercepts this transaction and re-submits the same signature multiple times.

  3. The contract accepts the signature repeatedly, since no nonce or s_voteNumber is used to invalidate reused signatures.

Tools Used

Recommendations

Nonce Implementation: Include a nonce for each voter, ensuring that each vote submission is unique. If a signature is reused, the nonce would prevent it from being accepted again.

Example:

contract RankedChoice is EIP712 {
...
+ mapping (address =>(mapping(bytes32 => bool)) public nonce;
// Inside rankCandidatesBySig
function rankCandidatesBySig(
address[] memory orderedCandidates,
bytes memory signature,
uint256 nonce
) external {
if(s_voterNonces[msg.sender][nonce]) revert throwCustomERROR();
bytes32 structHash = keccak256(abi.encode(TYPEHASH, orderedCandidates, nonce));
...
s_voterNonces[msg.sender][nonce] = true;
}

Include s_voteNumber in Signature: Incorporating the s_voteNumber (current election round) in the signature hash ensures that each election requires a new signature. This strengthens security by tying signatures to specific voting periods.

contract RankedChoice is EIP712 {
...
// Inside rankCandidatesBySig
function rankCandidatesBySig(
address[] memory orderedCandidates,
bytes memory signature,
+ uint256 s_voteNumber
) external {
- bytes32 structHash = keccak256(abi.encode(TYPEHASH, orderedCandidates));
+ bytes32 structHash = keccak256(abi.encode(TYPEHASH, orderedCandidates, s_voteNumber));
...
}
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.