In the BaseGauge contract, new accounts have their userStates[account].rewardPerTokenPaid being zero, allowing users with non-zero weight to call getReward() and claim rewards without staking any tokens. This occurs because the checkpoint() function triggers updateReward(msg.sender), which sets state.rewards for the caller without properly initializing their reward state.
The BaseGauge::earned() function calculates the rewards for an account based on the difference between the current reward per token and the amount of rewards the account has already been paid. For new users, the userStates[account].rewardPerTokenPaid value is zero. This results in the formula:
Since userStates[account].rewardPerTokenPaid is zero for new accounts, the entire getRewardPerToken() value is effectively used when calculating the reward. If an account has a non-zero weight, it can claim rewards even if no tokens have been staked, as the rewardPerTokenPaid is not properly initialized to reflect the current reward rate at the time of account creation.
This vulnerability allows users to claim rewards from the BaseGauge contract without actually staking any tokens.
vscode
The userStates[account].rewardPerTokenPaid for new users should be initialized to the current reward per token at the time the account is created. This ensures that users cannot claim rewards without staking any tokens.
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.