Status DataClose notification

VeChain Disclosed Report

Audit Report

Double Decrease of Effective Stake Leads to DoS and Permanent Loss of Funds

Target

Target is hidden

This information is not publicly available.

Vulnerability details

An issue in the requestDelegationExit() and unstake() functions allows the effective stake of a validator to be decreased twice for the same delegation. When a user with an ACTIVE delegation calls requestDelegationExit() and the validator subsequently exits, calling unstake() will either cause an underflow revert (DoS) or corrupt the validator's accounting. This results in users being permanently unable to unstake their tokens and retrieve their staked VET, leading to complete loss of funds. The issue stems from the fact that both requestDelegationExit() and unstake() call _updatePeriodEffectiveStake() with _isIncrease = false under certain conditions, without proper guards to prevent double-decreasing.

In the requestDelegationExit() function, when a delegation has ACTIVE status, the function:

  1. Calls signalDelegationExit() to mark the exit (line 555)
  2. then decreases the effective stake
_updatePeriodEffectiveStake($, delegation.validator, _tokenId, completedPeriods + 2, false);

The delegationId mapping is NOT cleared in this case, meaning the token still has a valid delegation record.

In the unstake() function, when unstaking a token with EXITED status and an exited validator:

  1. Withdraws the delegation
  2. Gets the validator status
  3. Decreases effective stake again if validator is EXITED
if (
    currentValidatorStatus == VALIDATOR_STATUS_EXITED ||
    delegation.status == DelegationStatus.PENDING
) {
    _updatePeriodEffectiveStake(
        $,
        delegation.validator,
        _tokenId,
        oldCompletedPeriods + 2,
        false // decrease
    );
}

The _updatePeriodEffectiveStake() function contains the following snippet, which will underflow and revert due to currentValue < effectiveStake

uint256 updatedValue = _isIncrease
    ? currentValue + effectiveStake
    : currentValue - effectiveStake;

Impact

The revert above effectively causes a DoS and locks the user's VET in the contract permanently

Validation steps

I have supplied a PoC below

Attachments

Attachments are hidden

This information is not publicly available.

Comments are hidden

This information is not publicly available.