The distributeRewards
function fails to update state after distributing rewards. This omission permits an attacker to trigger duplicate reward distributions for the same gauge, draining reward funds.
The distributeRewards
function computes a reward via the _calculateReward
call and then immediately calls IGauge(gauge).notifyRewardAmount(reward)
without updating any state to mark that rewards have been distributed for the current period.
This design flaw breaks the guarantee a gauge receives a single reward distribution per period. As a malicious input, an attacker can repeatedly call distributeRewards
for a specific gauge, and each call will trigger reward distribution without any check to prevent duplicate emissions.
This issue allows a single user to drain the rewards allocated to gauges. It produces high financial impact because an attacker repeatedly collects the same payout and depletes the system’s funds. The scenario is highly probable if the contract is publicly accessible and contains substantial reward balances, and the bug is directly exploitable without additional prerequisites.
Manual Review
Deploy or fork the affected contract with a funded reward pool.
Call distributeRewards(gauge)
successfully to receive the calculated reward.
Immediately call distributeRewards(gauge)
again to obtain the same reward repeatedly.
No state variable prevents endless identical distributions.
Prevent duplicate reward distributions by updating state after each reward emission. Implement a timestamp or distribution counter that tracks when rewards are distributed for each 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.