Status DataClose notification

VeChain Disclosed Report

User Funds get stucked in the contract when validators exits.

Company
Created date
Dec 08 2025

Target

hidden

Vulnerability Details

Summary

The system decreases a user’s effective stake when they request a delegation exit and then decreases it again when they later call unstake() if the validator has already exited. Because the validator is already in an exited state, the second decrease is performed using a later period index, causing _updatePeriodEffectiveStake() to underflow during:

updatedValue = currentValue - effectiveStake;

This results in a panic(0x11) arithmetic underflow, reverting unstake(). Since unstake() is the only mechanism for the user to retrieve their staked VET, the user’s funds become permanently stuck in the Stargate contract, with no recovery path.

Vulnerability Details

Relevant Code Paths

When requestDelegationExit() is called, the contract immediately reduces the user's effective stake:

_updatePeriodEffectiveStake(
    $, 
    delegation.validator, 
    _tokenId, 
    completedPeriods + 2, 
    false
);

Later, if the validator exits before the user calls unstake(), the unstake() function performs another decrease:

if (
    currentValidatorStatus == VALIDATOR_STATUS_EXITED ||
    delegation.status == DelegationStatus.PENDING
) {
    (, , , uint32 oldCompletedPeriods) =
        $.protocolStakerContract.getValidationPeriodDetails(delegation.validator);

@>>    _updatePeriodEffectiveStake(
        $,
        delegation.validator,
        _tokenId,
        oldCompletedPeriods + 2,
        false // decrease again
    );
}

Inside _updatePeriodEffectiveStake the underflow occurs:

uint256 updatedValue = _isIncrease
    ? currentValue + effectiveStake
    : currentValue - effectiveStake;  // underflows on second decrease

Because the second decrease subtracts the same effectiveStake from a smaller currentValue, the result becomes negative, causing a panic(0x11). This reverts the unstake() call entirely.

As a result, the user can never unstake or retrieve their VET, leaving their funds permanently stuck inside the Stargate contract.

Recommendation

I will recommend to guard to ensure effective stake is only decreased once per delegation lifecycle and also we don't try to reduce effective stake for period when there is no stakers.

Validation steps

Let's follow this flow again now, we can easily verify the bug, although i implemented the flow using hardhat test tool, to create a simple proof-of-concept:

  1. Stake VET with a validator to create a normal delegation.

  2. Call requestDelegationExit() —> observe that the contract reduces the delegation’s effective stake once.

  3. set the validator status to EXIT.

  4. Now call unstake() —> the contract tries to decrease effective stake again.

  5. The second decrease uses a later period index, causing currentValue —> effectiveStake → arithmetic underflow (panic 0x11).

  6. The unstake() reverts, and the user cannot withdraw their staked VET anymore.

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Critical
Bounty$612
Visibilitypartially
VulnerabilityDoS with (Unexpected) revert
Participants
hidden