AOSSIE-Org / AOSSIE-Org/Agora-Blockchain

fix(RankedBallot): Duplicate candidate IDs in vote array allow vote manipulation

オープン
#244 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
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 はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。