What is DualDefense?
DualDefense is a service that combines traditional security audits with HackenProof’s crowdsourced audits, powered by our community of ethical hackers. After a project completes its main audit, HackenProof bug hunters additionally review the code.
If critical bugs are found during the Crowdsourced Audit period, rewards are covered by the DualDefense Flash Pool — a fund supported by the staking community. This unique model prevents unexpected costs from being shifted to the project itself.
Auditors, the staking community, and bug hunters all work together to protect digital systems. By joining DualDefense, projects of any type — from Web3 smart contracts to traditional Web2 applications — gain maximum protection and engage a diverse security research community to uncover vulnerabilities before they can affect users.
About VeChain
VeChain is a public blockchain platform designed to connect blockchain technology with real-world action, making impact measurable, verifiable, and economically meaningful. Its ecosystem focuses on tracking real-world behavior on-chain and turning it into transparent, reward-driven outcomes.
VeChain has been listed on HackenProof since May 2018 and has consistently treated security as an ongoing process. Over the years, the project has launched three bug bounty programs and two DualDefense audits, reinforcing its approach to continuous review rather than one-off assessments.
A core pillar of VeChain’s technical roadmap is Stargate, a smart-contract suite introduced as part of the upcoming Hayabusa hard fork. Stargate defines how VET holders delegate stake to validator nodes, how delegation exits are handled, and how rewards are calculated and distributed — making it a critical component of both network security and economic fairness.
The DualDefense Finding
The VeChain Stargate smart contracts were reviewed under a DualDefense audit that ran from November 17, 2025 to December 10, 2025. During this period, an independent security researcher identified a critical logic flaw affecting delegation reward calculations.
The vulnerability allowed a delegator who had already exited staking to continue claiming VTHO rewards for future validator periods. Because delegation rewards are distributed from a fixed per-period pool, this behavior resulted in rewards being incorrectly diverted away from active delegators.
The finding was classified as critical under DualDefense’s impact criteria, as it enabled the theft of unclaimed yield from other users. VeChain promptly rewarded the researcher with $1,530, resolving the issue through responsible disclosure before any exploitation occurred.
The Delegator That Never Left: Vulnerability Mechanics
Bottom line: Due to a flaw in how claimable reward periods were calculated, a delegator who had exited staking could continue claiming rewards for future periods — effectively receiving yield they were no longer entitled to.
In Stargate, delegators stake VET and delegate through NFTs. For each validator period, a fixed amount of rewards is allocated and distributed proportionally among active delegators only. Once a delegator exits, their NFT should stop participating in future reward periods.
The vulnerability originated in the logic responsible for determining which validator periods were still claimable for a given delegation NFT. When a delegation exit occurred, the contract recorded an endPeriod to mark the last eligible reward window. However, a boundary condition caused delegations where endPeriod matched the next claimable period to be treated as if they were still active.
As validator periods continued to advance, this logic flaw caused the range of “claimable” periods for an exited NFT to keep growing over time. In practice, the system continued to recognize the delegation as eligible for rewards long after it had formally exited.
*The following section is based on the original vulnerability report submitted by the researcher.
Impacted components
- Contract:
Stargate–packages/contracts/contracts/Stargate.sol - Core functions:
_claimableDelegationPeriods(private view)_claimRewards(internal)claimableRewards(view)claimRewards(external)
Vulnerability Description
In Hayabusa Stargate, delegators stake VET and delegate via NFTs. For each validator period, the protocol computes:
- Total delegator rewards for that validator and period (in VTHO).
- Each delegator’s share, proportional to their effective stake.
Once a delegator exits, their NFT should stop participating in rewards for future periods. Only delegators who are still active in those periods should receive the yield.
However, due to a bug in the reward window calculation (_claimableDelegationPeriods), a delegator who has already exited can continue to have a growing range of “claimable periods” far after their exit. When combined with the reward calculation formula, this allows the exited NFT to keep claiming VTHO from periods where they are no longer part of the delegator set.
Because the total getDelegatorsRewards(validator, period) is fixed per period, any extra rewards granted to an exited NFT necessarily come out of the pool that belongs to active delegators. This is effectively stealing yield from other users, and fits HackenProof’s “Stealing or loss of end‑user funds” / “Theft of unclaimed yield” classification.
Root cause (code‑level)
The bug sits in _claimableDelegationPeriods, which is used by both claimableRewards (view) and _claimRewards (state‑changing).
Relevant code (simplified):
function _claimableDelegationPeriods(
StargateStorage storage $,
uint256 _tokenId
) private view returns (uint32, uint32) {
uint256 delegationId = $.delegationIdByTokenId[_tokenId];
if (delegationId == 0) return (0, 0);
(address validator, , , ) = $.protocolStakerContract.getDelegation(delegationId);
if (validator == address(0)) return (0, 0);
(uint32 startPeriod, uint32 endPeriod) =
$.protocolStakerContract.getDelegationPeriodDetails(delegationId);
(, , , uint32 completedPeriods) =
$.protocolStakerContract.getValidationPeriodDetails(validator);
uint32 currentValidatorPeriod = completedPeriods + 1;
uint32 nextClaimablePeriod = $.lastClaimedPeriod[_tokenId] + 1;
if (nextClaimablePeriod < startPeriod) {
nextClaimablePeriod = startPeriod;
}
// ended delegations
if (
endPeriod != type(uint32).max &&
endPeriod < currentValidatorPeriod &&
endPeriod > nextClaimablePeriod
) {
return (nextClaimablePeriod, endPeriod);
}
// treat as active/pending
if (nextClaimablePeriod < currentValidatorPeriod) {
return (nextClaimablePeriod, completedPeriods);
}
return (0, 0);
}
Key observations
- When a delegation exit is signalled in the mock
ProtocolStaker,endPeriodis set tocompletedPeriods + 1, i.e. the first period after the last completed period at the time of exit. - The “ended delegation” branch only triggers when
endPeriod > nextClaimablePeriod. The equality case (endPeriod == nextClaimablePeriod) is not treated as ended.
Consider this timeline for a delegator A on a validator:
startPeriod = 1- Delegation exit is signalled at some point, and
endPeriodis set (e.g.endPeriod = 10). - A has already called
claimRewardsenough times so thatlastClaimedPeriod = endPeriod, i.e. they are fully caught up until the last active period. - Time passes and the validator keeps producing blocks. Now
completedPeriods = 20andcurrentValidatorPeriod = 21.
At this point:
nextClaimablePeriod = lastClaimedPeriod + 1 = endPeriod + 1 = 11.endPeriod < currentValidatorPeriodis true (10 < 21), so the delegation is in the “ended” region.- But
endPeriod > nextClaimablePeriodis false (10 > 11 is false), so the “ended” branch is not taken. - Control falls through to the “active/pending” branch:
if (nextClaimablePeriod < currentValidatorPeriod) {
// 11 < 21 is true
return (nextClaimablePeriod, completedPeriods); // returns (11, 20)
}
This effectively treats the delegation as if it were still active up to completedPeriods, even though the user exited at endPeriod. As completedPeriods grows over time, the lastClaimablePeriod for this exited NFT also keeps growing.
Later, _claimRewards uses this window:
(uint32 firstClaimablePeriod, uint32 lastClaimablePeriod) =
_claimableDelegationPeriods($, _tokenId);
uint256 claimableAmount = _claimableRewards($, _tokenId, 0);
...
$.lastClaimedPeriod[_tokenId] = lastClaimablePeriod;
VTHO_TOKEN.safeTransfer(tokenOwner, claimableAmount);
The actual per‑period reward for a token is computed as:
uint256 delegationPeriodRewards =
$.protocolStakerContract.getDelegatorsRewards(validator, _period);
uint256 effectiveStake = _calculateEffectiveStake($, _tokenId);
uint256 delegatorsEffectiveStake =
$.delegatorsEffectiveStake[validator].upperLookup(_period);
if (delegatorsEffectiveStake == 0) return 0;
return (effectiveStake * delegationPeriodRewards) / delegatorsEffectiveStake;
Important detail:
- When the delegation is ended, the token’s effective stake is removed from
delegatorsEffectiveStake[validator]for future periods (via_updatePeriodEffectiveStake(..., false)inrequestDelegationExit). - However,
_calculateEffectiveStake($, _tokenId)still returns a non‑zero effective stake for the NFT (based on its level and staked VET) even when it has exited.
As a result:
- For a period after the exit, delegatorsEffectiveStake only includes the stake of active delegators.
- When the exited NFT calls
claimRewards, it computes a numerator using its full effective stake, divided by the sum of active delegators’ stake. - This yields a positive reward for the exited NFT from periods where it is no longer part of the delegator set.
Since the underlying delegatorsRewards(validator, period) pool is fixed, these extra rewards must be funded by diluting the rewards that active delegators should receive.
Validation steps
The following steps can be reproduced using the existing Hardhat test setup and mocks.
I. Environment
- Use Hardhat in‑memory network.
- Deploy contracts via
getOrDeployContracts({ forceDeploy: true, config }), withconfigcoming fromcreateLocalConfig(). - Use
ProtocolStakerMockas the staking backend, where:getDelegatorsRewards(validator, period)returns a fixed non‑zero amount for each period up tocompletedPeriods + 1.
II. Actors
- User A (“exiting delegator”).
- User B (“remaining active delegator”).
- A single validator address, configured as ACTIVE.
III. Initial staking & delegation
- Both A and B stake the same level (same
vetAmountRequiredToStakeandscaledRewardFactor) and delegate to the same validator. - Their effective stakes are identical.
IV. Advance validator periods and claim up to a checkpoint
- Advance
completedPeriodsinProtocolStakerMockto a valueCviahelper__setValidationCompletedPeriods. - Have both A and B call
claimRewardsonce, solastClaimedPeriodfor both NFTs is approximatelyC(they are fully caught up).
V. User A requests exit
- A calls
requestDelegationExit(tokenIdA). - In the mock, this sets
endPeriodfor A’s delegation and marks it as exiting. After enough periods, A’s status becomes EXITED.
VI. Advance additional periods with B still active
- Advance
completedPeriodsseveral more steps while B remains delegated to the validator. - At this point, B is the only active delegator on that validator for new periods.
VII. Observe claimable rewards for A (exited) and B (active)
- Query
claimableRewards(tokenIdA)andclaimableRewards(tokenIdB)after the extra periods. - Because of the bug:
- A (who has exited) still has a strictly positive
claimableRewards. - B (still active) also has strictly positive
claimableRewards.
- A (who has exited) still has a strictly positive
VIII. Interpretation
- For each post‑exit period, the total pool of delegator rewards is fixed
- Yet over these periods, both:
- A claims a non‑zero amount, and
- B also claims a non‑zero amount.
- Since A should have no stake during these periods, any rewards paid to A are effectively taken from the pool that should belong exclusively to active delegators like B.
Turning Threats into Lessons
The VeChain Stargate case highlights why DualDefense plays a critical role in securing complex, long-running protocol logic. By combining traditional audits with community-driven security research and a staking-backed reward pool, DualDefense helps projects identify subtle vulnerabilities before they impact users.
If your protocol relies on staking, reward distribution, or evolving on-chain state, book a call with a HackenProof security expert to explore how DualDefense can strengthen your security posture. Together, we help build safer and more resilient decentralized systems — one DualDefense program at a time.



