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.
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, 12Correct behavior (fix):
// Check 1: endPeriod >= nextClaimablePeriod
if (10 >= 10) // TRUE
return (10, 10) // ✅ Only period 10Vulnerability 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..15A 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 checkingendPeriodagainstnextClaimablePeriod.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?