It appears that on a fresh stake, $.userValidatorRewardPerTokenPaidTimestamp is only updated for active reward tokens and not for historical (previously removed) reward tokens. This creates a window where a user can receive unauthorized rewards.
Impact: User can steal rewards (theft of unclaimed yield).
Vulnerability Details
1
Scenario step
Reward token PUSD existed and is removed at timestamp X.
2
Scenario step
Post removal, User A stakes 10e18 tokens.
3
Scenario step
User A immediately unstakes 10e18 tokens. User A has 0 staked tokens.
4
Scenario step
Later, PUSD is added again at timestamp X+1.
5
Scenario step
User B stakes while PUSD is active.
6
Scenario step
At X+500 seconds User B stakes again and PUSD is removed.
7
Scenario step
User A stakes a very large amount at X+500 seconds. Since PUSD is not an active token, its userValidatorRewardPerTokenPaidTimestamp remains X (the old timestamp).
8
Scenario step
User A immediately claims and receives rewards for the full 500 seconds (from X to X+500) even though they shouldn't be entitled to them.
Impact Details
User can steal rewards.
Recommendation
Update _initializeRewardStateForNewStake to iterate all historical reward tokens instead of just $.rewardTokens to ensure state is updated properly for all reward tokens (including ones that were previously removed).