AOSSIE-Org / AOSSIE-Org/Agora-Blockchain
fix(RankedBallot): Duplicate candidate IDs in vote array allow vote manipulation
- 主要言語
- JavaScript
- スター
- 97
- フォーク
- 199
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Issue Description
**File:** `blockchain/contracts/ballots/RankedBallot.sol`
The `vote()` function in `RankedBallot.sol` does not validate that each candidate ID in the input array is unique. A voter can submit a `voteArr` like `[0, 0, 0]` to assign 1st-place, 2nd-place, and 3rd-place points all to candidate 0, inflating that candidate's score by 3x.
#### Root Cause
```solidity
function vote(uint[] memory voteArr) external onlyOwner {
uint totalCandidates = candidateVotes.length;
if (voteArr.length != totalCandidates) revert VoteInputLength();
for (uint i = 0; i < totalCandidates; i++) {
// No uniqueness check — voteArr[0,0,0] lets candidate 0 get all points
candidateVotes[voteArr[i]] += totalCandidates - i;
}
}
```
There are two additional missing validations:
1. No bounds check: `voteArr[i]` could be >= `totalCandidates`, causing an out-of-bounds array access (panic revert, no custom error).
2. No uniqueness check: the same candidate ID can appear multiple times, violating ranked-choice voting semantics.
#### Expected Behavior
`voteArr` must be a **permutation** of `[0, 1, ..., totalCandidates-1]`:
- Each candidate ID appears **exactly once**
- No out-of-bounds ID is accepted
#### Proposed Fix
Add two new custom errors (`InvalidCandidateID`, `DuplicateCandidateID`) and validate inside `vote()`:
```solidity
error InvalidCandidateID();
error DuplicateCandidateID();
function vote(uint[] memory voteArr) external onlyOwner {
uint totalCandidates = candidateVotes.length;
if (voteArr.length != totalCandidates) revert VoteInputLength();
bool[] memory seen = new bool[](totalCandidates);
for (uint i = 0; i < totalCandidates; i++) {
uint candidateId = voteArr[i];
if (candidateId >= totalCandidates) revert InvalidCandidateID();
if (seen[candidateId]) revert DuplicateCandidateID();
seen[candidateId] = true;
candidateVotes[candidateId] += totalCandidates - i;
}
}
```
#### Severity
**High** — directly exploitable to manipulate election results permanently on-chain.
### Record
- [x] I have synced all my node versions as mentioned in the project
- [x] I am using the same version of npm as is the project
- [x] My current branch is in sync with the development branch
- [x] I want to work on this issue
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
評価
この issue はまだ評価されていません。