In the GaugeController contract, the vote function allows users to allocate weight to a gauge. However, the mapping that should track the user's previous vote weight (userGaugeVotes[msg.sender][gauge]) is never updated after a vote. As a result, each vote is treated as if the user has no previous vote, enabling them to repeatedly vote and inflate the gauge's weight artificially.
What Went Wrong:
The vote function includes the following code:
The variable oldWeight is meant to capture the user's previous vote weight so that the gauge's total weight can be adjusted by subtracting the old value and adding the new one. However, the mapping userGaugeVotes[msg.sender][gauge] is never updated after the vote. This means oldWeight is always zero, and the gauge weight update simplifies to:
Consequently, users can repeatedly cast votes with non-zero weights and continuously add to the gauge's weight without any subtraction of prior votes.
Why It Matters:
Since gauge weight directly influences reward allocation, this flaw allows a malicious user to inflate the gauge's weight arbitrarily by continuously voting. This manipulation can divert rewards away from honest participants, undermining the fairness of the voting and reward distribution system.
User Scenario:
Initial Vote: A user votes with a weight of 5000. Ideally, userGaugeVotes[user][gauge] should record 5000, but it remains 0.
Subsequent Vote: The user votes again with a weight of 5000. Since the previous vote was not recorded, the system treats this as an additional 5000 weight.
Result: By repeating this process, the user can inflate the gauge's weight repeatedly, thereby capturing a larger share of rewards.
Unfair Reward Distribution:
Inflated gauge weights lead to disproportionate rewards for the manipulated gauge, disadvantaging other participants.
Economic Imbalance:
The manipulation skews the reward distribution mechanism, potentially leading to a concentration of rewards among a few malicious users.
Governance Risk:
Excessive gauge weight could influence governance decisions, allowing attackers to exert undue control over protocol parameters and decisions.
Manual Code Review: We analyzed the vote function and the corresponding _updateGaugeWeight logic, identifying that the userGaugeVotes mapping is never updated, allowing repeated inflation of gauge weight.
Update the Vote Mapping:
After processing a vote, update the user's vote weight in the mapping to reflect the new value:
solidity
Copy
Edit
userGaugeVotes[msg.sender][gauge] = weight;
Implement Voting Limits:
Consider adding additional checks to prevent abuse, such as limits on the frequency or cumulative weight a user can assign to a single gauge.
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.