57015 sc medium unbounded array loop

Submitted on Oct 22nd 2025 at 17:03:38 UTC by @pawps for Audit Comp | Belongarrow-up-right

  • Report ID: #57015

  • Report Type: Smart Contract

  • Report severity: Medium

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

Impacts:

  • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Vulnerability Details

The unbounded Stake[] array in the Staking contract causes a grief vector that allows users or an attacker to trigger an out-of-gas (OOG) revert when a user tries to withdraw their funds. Withdraw logic loops over the entire array (_consumeUnlockedSharesOrRevert for regular withdraw and _removeAnySharesFor for emergency withdraw), which can be made arbitrarily large by repeatedly depositing tiny stakes.

Example vulnerable loops:

function _consumeUnlockedSharesOrRevert(address staker, uint256 need) internal {
    Stake[] storage userStakes = stakes[staker];
    uint256 _min = minStakePeriod;
    uint256 nowTs = block.timestamp;
    uint256 remaining = need;

    for (uint256 i; i < userStakes.length && remaining > 0;) {
        Stake memory s = userStakes[i];
        ...
    }
}

Although the functions permit specifying an amount to withdraw (which can reduce iterations), an attacker can repeatedly deposit 1 wei (or other tiny amounts) under a victim's address. Because the data structure is FIFO and each deposit creates an entry, victims will either encounter OOG reverts on normal withdraws or be forced to withdraw in many very small recursive transactions to drain their funds.

Impact Details

  • Funds can become effectively locked in the contract for victims.

  • Out-of-gas reverts on withdraw attempts.

  • Grief attack where attacker need not profit but can lock other users' funds.

Mitigation

  • Enforce a whitelist for permitted depositors (per-user depositor whitelist).

  • Enforce a minimum stake amount so spam deposits are impractical.

  • Replace looping over the whole array with a start and end index (cursor-based processing) to allow incremental processing without iterating the entire array in a single transaction.

circle-exclamation

Proof of Concept

chevron-rightOOG Grief Attack PoC (truffle/mocha style)hashtag

References

Add any relevant links to documentation or code.

Was this helpful?