56941 sc critical staking vault vulnerable to first depositor donation attack
Submitted on Oct 21st 2025 at 23:34:16 UTC by @fullcounterhuner for Audit Comp | Belong
Report ID: #56941
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/belongnet/checkin-contracts/blob/main/contracts/v2/periphery/Staking.sol
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Summary
The Staking vault initializes with zero total supply and relies on the vanilla ERC4626 share math from Solady. Without any seeded liquidity or virtual share offsets, the first depositor can donate tokens to the vault and dramatically raise the price per share before others join. Severity: Critical, as later stakers can lose nearly all deposited assets to the initial attacker.
Finding Description
contracts/v2/periphery/Staking.sol inherits Solady's ERC4626 implementation and never seeds the share supply during initialize(). When the first user calls deposit(), the vault mints shares 1:1 against assets because totalSupply() equals zero, establishing the initial exchange rate. The contract also treats the token balance in the vault as canonical totalAssets() and does not adjust conversions with any virtual shares or assets. As a result, an attacker who controls the initial shares can transfer additional underlying tokens directly to the vault (or wait for reward distribution) to inflate the apparent asset balance while totalSupply() remains near zero. Subsequent users calling previewDeposit() or deposit() then receive almost no shares for their full contribution, effectively donating their assets to the first minter. After the one-day lock expires, the attacker redeems the inflated share for nearly all pooled funds.
Impact Explanation
Successful exploitation allows the attacker to drain the majority of assets supplied by later participants, resulting in high user fund loss and rendering the staking pool economically unusable.
Likelihood Explanation
The attack is straightforward, requires only being the first depositor, and leverages standard ERC4626 behavior without needing special privileges, making the likelihood high.
Proof of Concept
Attack steps (high level)
Attacker deposits a tiny amount (e.g., 1 wei) of LONG via
deposit()to mint the first share(s) at a 1:1 exchange rate becausetotalSupply() == 0.Attacker transfers a large amount of LONG directly to the vault (a raw token transfer), inflating
totalAssets()whiletotalSupply()remains near the initial tiny amount.Victim deposits a significant amount of LONG and receives almost zero shares due to the inflated exchange rate—effectively donating their deposit to the attacker.
After the withdrawal lock period (or via an emergency mechanism), the attacker calls
redeem()and withdraws nearly the entire vault balance, capturing the victim's funds.
PoC test (hardhat)
Recommendation
Consider seeding the vault with permanently locked liquidity or introducing virtual share and asset offsets so that unsolicited donations cannot skew the exchange rate. One approach could be to mint a fixed MINIMUM_SHARES amount to an irrecoverable address during initialization or to adopt Solmate-style virtual balance modifiers within the convertToAssets() and convertToShares() helpers.
End of report.
Was this helpful?