59421 sc high theft of unclaimed yield via incorrect period range calculation and lack of per user effective stake tracking

Submitted on Nov 12th 2025 at 08:25:35 UTC by @oxadwa for Audit Comp | Vechain | Stargate Hayabusaarrow-up-right

  • Report ID: #59421

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/Stargate.sol

Impacts:

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

  • Theft of unclaimed yield

Description

A critical vulnerability in the Stargate.sol contract allows exited delegators to steal VTHO rewards from active delegators. The vulnerability stems from two interconnected issues:

  1. Boundary condition bug in _claimableDelegationPeriods() (line 921): the function uses endPeriod > nextClaimablePeriod instead of endPeriod >= nextClaimablePeriod, causing it to return an incorrect period range when a user's last claimable period equals their exit period.

  2. Lack of per-user effective stake tracking: getDelegatorsEffectiveStake() tracks effective stake per validator and period, but not per individual delegator. This allows exited users to claim rewards from periods where they were no longer delegated, as long as other users remain delegated to the same validator.

When combined, these issues enable a user who has exited their delegation to claim a share of rewards that rightfully belong to users who remained delegated during those periods.

Vulnerability Details

Root Cause Analysis

Issue 1: Boundary Bug (Line 921 in Stargate.sol)

When endPeriod == nextClaimablePeriod (e.g., both equal 10), this condition fails and falls through to: return (nextClaimablePeriod, completedPeriods);

This incorrectly returns periods beyond the user's exit period.

Issue 2: Shared Effective Stake Tracking

The system tracks effective stake using:

periodValidatorEffectiveStake[period][validator] β€” Total for ALL delegators

When calculating a user's reward share in _claimRewards():

The system:

  1. Gets the user's token effective stake (still exists even after exit)

  2. Divides by the total validator effective stake for that period

  3. Cannot distinguish if the user was actually delegated during that period

Therefore, an exited delegator can still receive a proportional share of rewards for periods during which they were not actually delegated.

Attack Scenario

1

Setup: User A delegates and accumulates rewards

  • Periods 1–9: User A delegates to Validator X and accumulates rewards.

2

User A exits during period 10

  • Period 10: User A requests delegation exit (sets endPeriod = 10).

  • Period 10: User A claims rewards for periods 2–9 (lastClaimedPeriod = 9).

3

Another delegator joins

  • Period 10: User B delegates to Validator X (now 2 active delegators).

4

Time advances

  • Periods 11–14: User B remains delegated and accumulates rewards. User A is considered EXITED.

5

Exploit: User A claims again

  • Period 15: User A calls claimRewards().

  • Due to the boundary bug and shared effective stake tracking:

    • _claimableDelegationPeriods() incorrectly returns (10, 14) instead of (10, 10).

    • User A's effective stake still exists and is used to compute shares.

    • User A receives a share of rewards for periods 11–14 despite being exited, effectively stealing from User B.

Impact Details

triangle-exclamation

References

  • https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/blob/e9c0bc9b0f24dc0c44de273181d9a99aaf2c31b0/packages/contracts/contracts/Stargate.sol#L916-L930

  • https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/blob/e9c0bc9b0f24dc0c44de273181d9a99aaf2c31b0/packages/contracts/contracts/Stargate.sol#L715-L721

  • https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/blob/e9c0bc9b0f24dc0c44de273181d9a99aaf2c31b0/packages/contracts/contracts/Stargate.sol#L829-L855

Proof of Concept

chevron-rightReproduction test (paste under Rewards.test.ts)hashtag
  • Fix the boundary condition in _claimableDelegationPeriods():

    • Change endPeriod > nextClaimablePeriod to endPeriod >= nextClaimablePeriod so that when endPeriod == nextClaimablePeriod the function returns the correct range (nextClaimablePeriod, endPeriod).

  • Add per-user effective stake tracking (or otherwise ensure reward shares are computed only for delegators who were active during the claimed period):

    • Track effective stake per (period, validator, delegator) or include a mechanism to exclude exited delegators from receiving shares for periods after their endPeriod.

    • Ensure getDelegatorsEffectiveStake() and reward accounting use per-user participation information for each period.

  • Audit related reward accounting paths to ensure no other boundary conditions or shared-aggregates can be abused by exited delegators.


If you want, I can:

  • Extract the exact lines in Stargate.sol and propose a minimal patch (diff) for the boundary condition, and suggest data structures/approaches for per-user stake tracking.

Was this helpful?