For the complete documentation index, see llms.txt. This page is also available as Markdown.

60069 sc high incorrect claimable period calculation leading to attacker keep claiming even after exiting the delegation

Submitted on Nov 18th 2025 at 07:49:27 UTC by @Bizarro for Audit Comp | Vechain | Stargate Hayabusa

  • Report ID: #60069

  • 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:

    • Protocol insolvency

    • Theft of unclaimed yield

Description

Brief / Intro

The checks in _claimableDelegationPeriods() are not sufficient to prevent a delegator from claiming rewards after their delegation has ended. Off-by-one and missing boundary checks allow claiming periods beyond the delegation end.

1

Vulnerability detail — off-by-one when endPeriod equals nextClaimablePeriod

In _claimableDelegationPeriods() when a delegation ends exactly at the next claimable period, the function can incorrectly return periods beyond the delegation's end, allowing claims for periods after exit.

Problematic code (logic):

if (
    endPeriod != type(uint32).max &&
    endPeriod < currentValidatorPeriod &&
    endPeriod > nextClaimablePeriod  // ❌ WRONG: Should be >= 
) {
    return (nextClaimablePeriod, endPeriod);
}

// If above check fails, falls through to:
if (nextClaimablePeriod < currentValidatorPeriod) {
    return (nextClaimablePeriod, completedPeriods);  // ❌ Returns too many periods
}

Example path:

  • User delegated from period 5 to period 10.

  • User requested exit at period 9 → endPeriod = 10.

  • User claimed up to period 9 → lastClaimedPeriod = 9.

  • nextClaimablePeriod = lastClaimedPeriod + 1 = 10.

  • Validator: completedPeriods = 12, currentValidatorPeriod = 13.

Evaluation:

// Check 1: endPeriod > nextClaimablePeriod
if (10 > 10) // FALSE - skip

// Falls through to Check 2: nextClaimablePeriod < currentValidatorPeriod  
if (10 < 13) // TRUE
    return (10, 12) // ❌ WRONG: Returns periods 10, 11, 12

Correct behavior (fix):

// Check 1: endPeriod >= nextClaimablePeriod
if (10 >= 10) // TRUE
    return (10, 10) // ✅ Only period 10
2

Vulnerability detail — missing check when nextClaimablePeriod > endPeriod

When a delegation has ended and the last claimed period equals the end period, the function can still return non-zero ranges (allowing further claims) because there's no explicit guard ensuring nextClaimablePeriod <= endPeriod. The logic falls through and returns claimable periods beyond the delegation end.

Relevant code flow:

if (
    endPeriod != type(uint32).max && // -> true 
    endPeriod < currentValidatorPeriod && // -> true
    endPeriod > nextClaimablePeriod  // -> false
) {
    return (nextClaimablePeriod, endPeriod); 
}

if (nextClaimablePeriod < currentValidatorPeriod) {
    return (nextClaimablePeriod, completedPeriods);  // -> claim from nextClaimablePeriod to completedPeriods.
}

Example path:

  • User delegated from period 5 to period 10.

  • User requested exit at period 9 → endPeriod = 10.

  • User claimed up to period 9 → lastClaimedPeriod = 9.

  • nextClaimablePeriod = 10.

  • Validator: completedPeriods = 9, currentValidatorPeriod = 10.

  • User claims → updates lastClaimedPeriod = 10.

  • Later validator: completedPeriods = 15, currentValidatorPeriod = 16.

Evaluation:

// Check 1
if (10 != max32 && 10 < 16 && 10 > 11) // FALSE - skip

// Falls through to Check 2: nextClaimablePeriod < currentValidatorPeriod  
if (11 < 16) // TRUE
    return (11, 15) // ❌ WRONG: Returns periods 11..15

A missing check to ensure nextClaimablePeriod <= endPeriod (or returning (0,0) when nextClaimablePeriod > endPeriod) causes over-claiming.

Impact Details

  • Over-claiming rewards for periods after delegation exit.

  • Reduced funds available to honest delegators; potential protocol insolvency from excessive payouts.

References

  • Vulnerable file: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/blob/e9c0bc9b0f24dc0c44de273181d9a99aaf2c31b0/packages/contracts/contracts/Stargate.sol#L879C5-L934C6

Proof of Concept

Below instructions and code show how to reproduce the issue by instrumenting the contract and running a unit test.

Add a console.log to track the new effective values (example location): https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/blob/e9c0bc9b0f24dc0c44de273181d9a99aaf2c31b0/packages/contracts/contracts/Stargate.sol#L742

Example console log insertion:

Add this test in test/unit/Stargate/Rewards.test.ts and run yarn contracts:test:unit:

Expected test output (demonstrating the incorrect returned ranges):

(Full test logs available in the original report.)

Suggested fix (summary)

  • Change the strict > comparison to >= when checking endPeriod against nextClaimablePeriod.

  • Add a guard to return (0,0) or otherwise prevent claims when nextClaimablePeriod > endPeriod (i.e., ensure you never return claimable ranges that start after the delegation end).

(Do not add other changes — the above describes only the minimal intended logic fixes based on the report.)

Was this helpful?