#42345 [SC-Critical] Theft of User Funds in executeRewardDistributionYeet During Vesting Period

Submitted on Mar 23rd 2025 at 06:16:35 UTC by @testnate for Audit Comp | Yeet

  • Report ID: #42345

  • Report Type: Smart Contract

  • Report severity: Critical

  • Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/StakeV2.sol

  • Impacts:

    • Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

Brief/Intro

The executeRewardDistributionYeet function allows managers to distribute tokens that belong to users who have initiated the unstaking process but are still in the vesting period. This can lead to theft of users' funds, as demonstrated in the test case test_fundsLostDuringVestingPeriod. When users call startUnstake, their tokens are put into a vesting period but remain in the contract, where they're incorrectly counted as available rewards that managers can distribute.

Vulnerability Details

The issue occurs due to how accumulatedDeptRewardsYeet calculates "accumulated rewards":

function accumulatedDeptRewardsYeet() public view returns (uint256) {
    return stakingToken.balanceOf(address(this)) - totalSupply;
}

This calculation assumes that any tokens in the contract beyond the totalSupply are excess rewards. However, this is incorrect because it also includes tokens that are in vesting periods from users who have called startUnstake.

The vulnerability sequence:

  1. When a user calls startUnstake:

Their tokens are removed from balanceOf and totalSupply, but remain in the contract, marked only by a vestings struct.

  1. executeRewardDistributionYeet can then distribute these tokens:

A malicious or careless manager can distribute tokens that actually belong to users in the vesting period, causing them to permanently lose these funds.

Impact Details

This is a critical vulnerability that allows managers to steal or accidentally distribute users' funds:

  • Loss of User Funds: Users who have called startUnstake can lose 100% of their tokens in the vesting period if a manager calls executeRewardDistributionYeet.

  • Scale of Impact: The issue affects all users who enter the vesting period through startUnstake. Since the vesting period is 10 days long, this creates a large window where users' funds are at risk.

  • No Recovery Mechanism: Once tokens are sent to the zapper, there's no way for users to recover them. When they attempt to call unstake after the vesting period, the transaction fails due to insufficient token balance in the contract.

This is particularly problematic because users reasonably expect their tokens to be returned after the vesting period, but this vulnerability breaks this fundamental contract guarantee.

Proof of Concept

Proof of Concept

Add this contract in StakeV2.test.sol

Run forge test --use 0.8.20 -vvv --mt test_fundsLostDuringVestingPeriod

Was this helpful?