AOSSIE-Org / AOSSIE-Org/Agora-Blockchain

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

Offen
#244 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
JavaScript
Sterne
97
Forks
199
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### 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

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.