_applyStake doesn't sync userRewardPerTokenPaid with _rewardPerToken, allowing any staker to claim the full _rewardPerToken amount for their balance.
When staking with stakeFor, users are assigned to their old, but empty index (no stakes on this index).
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol/contracts/templegold/TempleGoldStaking.sol#L265
After that, _applyStake is called to update the _stakeInfos map. Notice how the updateReward modifier is called on _applyStake, but because it's a modifier, it's called before we update the _stakeInfos map.
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol/contracts/templegold/TempleGoldStaking.sol#L495
Since it's called before _stakeInfos is initialized, it will calculate claimableRewards and userRewardPerTokenPaid as 0.
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol/contracts/templegold/TempleGoldStaking.sol#L594
However, after the _applyStake call, our user has _stakeInfos map with their balances, but userRewardPerTokenPaid is 0. Now they would be able to call getReward and claim the full _rewardPerToken, even though they just staked.
Loss of funds. Users game the system.
Manual review
Inside _applyStake, manually sync userRewardPerTokenPaid to _rewardPerToken. This may require more code, as we also need to account for vesting.
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.