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 Hayabusa
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
Scenario (high-level)
A delegator delegates to an active validator.
Their delegation becomes active and they can claim rewards.
The delegator calls
requestDelegationExitwhile the validator is still active.requestDelegationExitcalls_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(likeunstake) to revert or block user funds.
Relevant code paths
requestDelegationExitdecreases 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);claimRewardscalls_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 byendPeriod, 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 > nextClaimablePeriodwill 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'
claimRewardsorunstake) 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.tsshowing the attack flow and the resulting balances and reverts.
Files and commands:
Add
local.tsintopackages/config/with this content (unchanged):
Create
test/integration/DelegationExitRewardsClaimBug.test.tswith 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
claimRewardsmultiple 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
claimRewardsreverts with an insufficient balance error.
Sample logs from the run (kept verbatim):
Notes / Mitigation Ideas (not exhaustive, for triage)
Ensure that when
requestDelegationExitis 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
_claimableDelegationPeriodsand 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?