52996 sc high users can claim rewards for newly added reward tokens even when the validator they staked for was inactive during some time interval

Submitted on Aug 14th 2025 at 15:41:04 UTC by @swarun for Attackathon | Plume Network

  • Report ID: #52996

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/facets/ValidatorFacet.sol

  • Impacts: Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

Brief / Intro

Suppose a validator was inactive for some time interval and during that time interval a new token got added. Users shouldn't receive rewards when the validator is inactive, but they will receive rewards when a new reward token was added during the inactive interval. This causes users to receive rewards for time intervals where there was no accumulation of rewards, which should not happen.

Vulnerability Details

When a new reward token is added while a validator is inactive, the logic creates reward checkpoints for all validators (including the inactive one) at the addition time. Later, when the validator is reactivated, a new checkpoint is created again at the activation time. Because the reward calculation logic splits time into segments based on checkpoints, this can result in a segment that covers the inactive interval with a non-zero effective reward rate (from the token addition checkpoint), producing rewards to stakers even though the validator was inactive during that time.

Impact Details

Users receive more rewards than they are eligible for.

References

https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/plume/src/facets/ValidatorFacet.sol#L252

Proof of Concept

1

Setup: validator made inactive while users are staked

Suppose the admin sets a validator inactive (without slashing) while users remain staked. The function used:

  • Validator becomes inactive at t = 0 with users still staked.

  • Validator remains inactive until t = 2 days.

2

Add a new reward token during inactivity

At t = 1 day (while the validator is inactive), a new reward token is added via:

  • This creates a reward-rate checkpoint for every validator (including the inactive one) at t = 1 day with a non-zero rate.

3

Validator reactivated and another checkpoint created

At t = 2 days the admin reactivates the validator. The active transition creates another checkpoint for all reward tokens at t = 2 days and resets timestamp caps:

  • Now the newly added token has two checkpoints for this validator: one at t = 1 day (added) and one at t = 2 days (reactivation).

4

Reward accumulation logic and how it miscomputes for the inactive interval

Important notes:

  • While the validator was inactive, the system prevents updating $.validatorRewardPerTokenCumulative[validatorId][token] due to timestamp caps (no reward accumulation while inactive).

  • Later, after reactivation and time passing, the cumulative RPT is updated, and a user triggers a claim.

Claim flow (relevant parts):

Main reward processing:

  • updateRewardsForValidatorAndToken ultimately calls core calculation logic which splits the period since the user's last update into segments based on distinct checkpoint timestamps (rate or commission changes).

5

How the segments cause incorrect rewards

The core loop computing rewards iterates segments between distinct timestamps (checkpoints). Simplified snippet:

  • In the scenario: distinctTimestamps includes t = 1 day (token addition) and t = 2 days (validator reactivated).

  • For the segment [1 day, 2 day], getEffectiveRewardRateAt at segmentStartTime (1 day) returns a non-zero rate (token was added).

  • segmentDuration = 1 day, userStakedAmount > 0, so gross reward is calculated and added to the user's rewards even though the validator was inactive during that segment.

  • This yields extraneous rewards for the inactive interval.

Was this helpful?