60102 sc high exited delegator could keep claiming rewards stealing them from active delegators which would then lead to freeze of funds

Submitted on Nov 18th 2025 at 17:55:17 UTC by @rzizah for Audit Comp | Vechain | Stargate Hayabusaarrow-up-right

  • Report ID: #60102

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

    • Theft of unclaimed yield

    • Smart contract unable to operate due to lack of token funds

    • Temporary freezing of funds for at least 24 hour

Description / Brief

For a delegator to exit delegation from an Active validator they call requestDelegationExit, which directly removes this delegator's stakes from effective stakes via _updatePeriodEffectiveStake.

If, after calling requestDelegationExit, the delegator does nothing further (doesn't unstake/redelegate) while the validator keeps completing periods, the delegator can repeatedly call claimRewards. The first claim is capped to the delegation end period (the requested exit time), but subsequent calls can continue to claim rewards that should belong to currently active delegators — effectively stealing rewards and potentially depleting the contract token balance, which may later block other delegators from claiming or unstaking.

Vulnerability Details

1

Scenario (high-level)

  • A delegator delegates to an active validator.

  • Their delegation becomes active and they can claim rewards.

  • The delegator calls requestDelegationExit while the validator is still active.

  • requestDelegationExit calls _updatePeriodEffectiveStake, which immediately decreases effective stake for future periods, but does not delete the delegation id while the validator is active (the delegation remains in status ACTIVE with a requested exit flag).

  • Time passes: the delegator does nothing further (doesn't unstake).

  • The validator continues completing periods. When the exited delegator later calls claimRewards, they can claim beyond the end period:

    • The first claim is capped at the end period (the requested exit).

    • Subsequent claims can claim rewards from the current active effective stake because the condition that would cap them no longer applies, allowing the exited delegator to keep claiming rewards intended for active delegators.

  • This results in theft of rewards and can leave the contract with insufficient token balance, causing other functions that rely on claimRewards (like unstake) to revert or block user funds.

2

Relevant code paths

  • requestDelegationExit decreases effective stake via:

    • https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L567-L569

    // decrease the effective stake
    _updatePeriodEffectiveStake($, delegation.validator, _tokenId, completedPeriods + 2, false);
  • claimRewards calls _claimRewards, which obtains claimable periods:

    • https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L790-L791

    (uint32 firstClaimablePeriod, uint32 lastClaimablePeriod) = _claimableDelegationPeriods($, _tokenId);
  • In _claimableDelegationPeriods, delegations that ended are capped by endPeriod, but the condition can be bypassed for subsequent calls:

    • https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L963-L973

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

    Because the state can be such that endPeriod > nextClaimablePeriod will never be true on later calls, an exited delegator may continue to be considered eligible to claim rewards beyond their intended end period. This allows an exited delegator to claim rewards that should be computed using current effective stakes (belonging to active delegators), draining the contract balance.

Impact Details

  • Stealing of rewards that should belong to active delegators.

  • Contract token balance depletion, which may cause later calls (e.g., other delegators' claimRewards or unstake) to revert due to insufficient token balance.

  • Temporary freezing of funds for other delegators until additional tokens are transferred into the contract to cover the shortfall.

The freeze can be remedied by transferring the missing token balance to the contract.

References

  • claimable delegation periods: https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L963-L973

  • _claimRewards: https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L790-L791

  • changing lastclaimedperiod: https://github.com/vechain/stargate-contracts/blob/877f294a132bf3fd9b51821c5f58b9f9e91c60c1/packages/contracts/contracts/Stargate.sol#L815-L816

Proof of Concept (POC)

This POC demonstrates how an exited delegator can repeatedly call claimRewards and extract rewards meant for active delegators. It includes:

  • A local config snippet to use a local environment.

  • A Hardhat integration test DelegationExitRewardsClaimBug.test.ts showing the attack flow and the resulting balances and reverts.

Files and commands:

  • Add local.ts into packages/config/ with this content (unchanged):

  • Create test/integration/DelegationExitRewardsClaimBug.test.ts with the provided test code (keeps original content unchanged). Then run:

The test script (excerpt) reproduces:

  • Two delegators delegate to the same active validator.

  • Delegator1 requests exit (state remains ACTIVE but requested to exit).

  • Validator completes multiple periods.

  • Delegator1 (exited) calls claimRewards multiple times:

    • The first claim yields rewards for periods they were active.

    • Subsequent claims extract additional rewards (stealing), increasing delegator1's balance and draining the contract.

  • Delegator2 (still active) then cannot claim due to insufficient contract balance and their claimRewards reverts with an insufficient balance error.

Sample logs from the run (kept verbatim):

chevron-rightClick to expand logshashtag

Notes / Mitigation Ideas (not exhaustive, for triage)

  • Ensure that when requestDelegationExit is called and the effective stake is decreased for future periods, the delegation's claimable periods and/or last claimed period state are updated in a way that prevents subsequent claims beyond the actual exit period.

  • Make sure _claimableDelegationPeriods and related state transitions cannot be manipulated by leaving a delegation in an ACTIVE-with-exit-request state that still permits claiming from current effective stake.

  • Consider revoking or adjusting rights to claim rewards immediately upon an exit request, or introducing a robust guard ensuring a delegation that has requested exit cannot continue to claim from future periods once their effective stake is adjusted.

  • Add unit/integration tests (like this POC) to validate no further claims are possible by exited delegators across validator period transitions.

If you want, I can:

  • Convert the POC test into a reduced reproducible script or a minimal unit test,

  • Suggest exact contract patches (code-level) to prevent this behavior, based on the referenced functions.

Was this helpful?