The rankCandidatesBySig() function in the RankedChoice contract allows voters to cast their ranked votes using an off-chain signature. However, the function does not verify whether the candidate rankings passed on-chain are the same as the ones signed off-chain by the voter. This opens up a vulnerability where an attacker can manipulate a legitimate voter's signed vote and pass different candidates to the contract.
The key issue in the rankCandidatesBySig() function is the lack of validation between the candidate rankings signed off-chain by the voter and the rankings passed on-chain by the user submitting the vote. Specifically, the function uses the voter's signature to recover their address but does not compare the data being signed (the orderedCandidates array) with the actual array submitted to the contract.
Here’s how the vulnerability occurs:
A legitimate voter signs an off-chain message containing their chosen candidate rankings (e.g., [candidate1, candidate2, candidate3]).
An attacker intercepts the signature but modifies the candidate rankings (e.g., [attacker1, attacker2, attacker3]) when submitting the vote on-chain.
The contract recovers the correct signer from the signature but does not verify that the rankings match what the signer intended to vote for.
Since the function does not check if the rankings submitted match the rankings that were signed, the attacker's manipulated candidate list is accepted.
This vulnerability allows an attacker to alter a legitimate voter’s ranked choice vote by changing the candidate list while using the voter’s valid signature. The effects of this include:
Vote Manipulation: The attacker can effectively control which candidates receive votes, leading to unfair election results.
Loss of Trust: Voters may lose confidence in the system if votes can be altered without detection, potentially compromising the integrity of the entire voting process.
ECDSA (Elliptic Curve Digital Signature Algorithm): This is used for recovering the voter's address from the signature. However, the vulnerability is due to not verifying the integrity of the signed message with the input data.
Validate Input Data: Modify the rankCandidatesBySig() function to compare the hash of the orderedCandidates array passed on-chain with the hash of the array that was signed off-chain.
Hash the orderedCandidates array using keccak256 and compare it with the hash that was signed by the voter.
Implement Integrity Check:
Check for Voter Validity: Ensure that the recovered signer is a valid voter and that the vote corresponds to their intended candidate rankings.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.