51369 sc high unbounded iteration gas dos in validatetokenforclaim

Submitted on Aug 2nd 2025 at 05:01:22 UTC by @BeastBoy for Attackathon | Plume Network

  • Report ID: #51369

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Protocol insolvency

    • Permanent freezing of funds

Description

When a reward token is inactive, _validateTokenForClaim reads the victim’s entire userValidators array and for each entry executes calculateRewardsWithCheckpointsView, which itself walks through every reward‑rate and commission checkpoint.

Because stakeOnBehalf(...) is public and uncapped, an attacker can call it repeatedly to append thousands of distinct validator IDs for any user. Once the token is delisted, every claim invocation on that token by the victim triggers the nested loops. The combined O(V×C) gas cost where V is the number of validators and C the number of checkpoints per validator quickly exceeds block gas limits, causing the claim to revert permanently.

Impact

Attacker can permanently prevent any user from withdrawing rewards for a removed token by forcing every claim to run out of gas.

Recommendation

Maintain each user’s validator set with an enumerable mapping to forbid duplicate entries and enforce a reasonable maximum size, or require explicit approval before stakeOnBehalf can add a validator and include a safeguard in _validateTokenForClaim that reverts early if the validator count exceeds a safe iteration threshold.

Proof of Concept

1

Setup victim and environment

The test demonstrates creating many validators and inflating a victim's validator array so that subsequent claim calls become too expensive and revert.

Key actions in this step:

  • Prepare a victim account and admin context.

  • Create many additional validators for the attack.

2

Inflate victim's validator array

The attacker uses stakeOnBehalf repeatedly to associate the victim with many validators (minimal stake each time), producing a very large userValidators array for the victim.

3

Remove the reward token

Remove (delist) the reward token to ensure _validateTokenForClaim executes the expensive validation path that iterates over the victim's validators and checkpoints.

4

Victim attempts to claim — expected revert due to gas exhaustion

When the victim calls claim(PLUME_NATIVE) (or claimAll()), the nested loops O(V×C) cause the call to run out of gas and revert, confirming the gas DoS.

5

Confirm all claim functions affected

The test demonstrates that claimAll() also fails, showing that all claim paths that trigger _validateTokenForClaim are blocked.

Full PoC test used to reproduce:

Was this helpful?