57717 sc medium attacker can spam tiny stakes to a victim and make their withdrawal run out of gas griefing dos
Submitted on Oct 28th 2025 at 12:17:54 UTC by @manvi for Audit Comp | Belong
Report ID: #57717
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/periphery/Staking.sol
Impacts:
Temporary freezing of NFTs for at least 24 hour
Griefing (attacker has no profit motive, but harms users or the protocol)
Unbounded gas consumption
Description
Brief / Intro
The Staking flow creates a fresh stake entry for every deposit(assets, receiver). Withdraw/redeem scans and pops across all of a user's stake entries. Because ERC-4626 allows deposit(…, receiver) by anyone, an attacker can spam thousands of tiny deposits to a victim, making the victim’s withdraw path O(n) and practically fail under normal gas — temporarily freezing their funds.
Vulnerability Details
While reviewing contracts/v2/periphery/Staking.sol:
Each call to
_deposit(...)appends a new stake entry. There is no merge/min-size/cap per user.The withdraw path (via the unlocked-shares consumer) iterates and pops entries until it gathers enough unlocked shares.
ERC-4626 allows
deposit(…, receiver)by anyone, so an attacker can create thousands of entries for the victim without their consent.From tests, once a victim's stake entry count is large (e.g., 5k–10k), withdraw/redeem becomes gas-bounded and reverts with typical gas settings. With fewer entries, the same call succeeds — this is a gas-scaling DoS rather than a logic bug.
Impact Details
Attacker can make a victim's withdraw uneconomical or revert due to gas limits.
Victim cannot withdraw under normal gas caps and would need exceptional gas or state changes.
Cost/effort for the attacker scales linearly with the number of attacker-created entries; the attack is cheap since attacker only needs to pay spam gas and needs no approvals or roles.
File referenced:
contracts/v2/periphery/Staking.sol
Proof of Concept
I wrote a Foundry test against the repo that:
Deploys
Stakingand a simple ERC-20 mock.Victim stakes normally.
Attacker loops
deposit(1, victim)thousands of times, creating thousands of victim entries.Advance time past the lock.
Call
withdrawfrom the victim with a low/typical gas cap → it reverts due to the O(n) scan; with a very high gas cap, it succeeds, proving gas-based DoS.
File location: poc/PoC_Staking_Griefing.t.sol
What the PoC proved
An arbitrary attacker can repeatedly call
deposit(…, receiver=victim)to create thousands of tiny stake entries for the victim (no merge/min-size guard in_deposit).When the victim later tries to withdraw, the contract's
_consumeUnlockedSharesOrRevertmust iterate across entries (O(n)) to assemble unlocked shares.The test shows that, after spam, a victim's withdraw reverts under a reasonable gas cap — demonstrating a practical griefing DoS.
The attacker needs no approvals/roles and does not take custody of the victim's funds — only pays spam gas, making the attack cheap and repeatable.
Mitigation approaches include:
Merge consecutive stakes for the same receiver into a single entry (or maintain aggregated balances per receiver + timestamped buckets).
Enforce a minimum deposit size or a per-receiver cap on pending stake entries.
Change withdraw logic to avoid linear scans over unbounded per-user arrays (e.g., use efficient data structures or index pointers, paginate, or allow users to sweep entries in smaller chunks). Note: Do not add any mitigation not already present in the original report — these are generic suggestions.
Was this helpful?