57766 sc medium attacker can permanently lock any user s funds

Submitted on Oct 28th 2025 at 19:10:02 UTC by @danial for Audit Comp | Belongarrow-up-right

  • Report ID: #57766

  • Report Type: Smart Contract

  • Report severity: Medium

  • Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/periphery/Staking.sol

  • Impacts:

    • Permanent freezing of funds

Description

Brief / Intro

The Staking contract allows attackers to deposit on behalf of any address and each deposit creates a new locked Stake entry in a per-user array. An attacker can spam thousands of tiny deposits for a victim so the victim’s stakes[victim] array becomes huge. Both normal withdraw and the emergency withdraw flows iterate that array; when it’s big enough the calls will run out of gas and revert. Result: victim’s funds become permanently locked.

Vulnerability Details

Anyone can deposit on behalf of any address in deposit() from ERC4626:

function deposit(uint256 assets, address to) public virtual returns (uint256 shares) {
    if (assets > maxDeposit(to)) _revert(0xb3c61a83); // `DepositMoreThanMax()`.
    shares = previewDeposit(assets);
    _deposit(msg.sender, to, assets, shares);
}

From _deposit() every deposit pushes a new stake entry:

The _consumeUnlockedSharesOrRevert() iterates the whole array:

The _removeAnySharesFor() also iterates the whole array:

1

Attack flow — step-by-step

  • Attacker calls deposit(1, victim) many times. stakes[victim] grows to N entries.

  • Victim calls deposit(100e18, victim). This pushes a new Stake entry into the array.

  • Attacker spam deposits again M times to same victim. Victim’s honest deposit entry ends up sandwiched inside a much larger array.

Effect on withdraws:

  • Normal withdraw uses _consumeUnlockedSharesOrRevert() which reads the whole stakes array and will revert due to out of gas when the array is large enough.

  • Emergency withdraw calls _removeAnySharesFor, which also iterates and performs swap-and-pop; it too will revert when the array is large enough.

Impact Details

Critical: attacker can permanently block a user’s ability to withdraw their tokens at low attack cost (small deposits + gas).

Proof of Concept

chevron-rightClick to expand PoC (Forge test)hashtag

Note: for simplicity, the PoC uses the Staking contract directly (not via proxy — comment the constructor in Staking.sol).

Run the test with: forge test --fork-url https://bsc-dataseed1.binance.org

Was this helpful?