The deposit function should add to a user's stakedAsset balance, which is used by cancelParticipation to refund the correct amount.
However, the deposit function uses an assignment (=) instead of addition (+=) when updating stakedAsset. It also allows msg.sender to deposit for a different receiver. An attacker can call deposit with the victim's address as the receiver and a dust amount, overwriting the victim's entire stake and setting their refundable balance to near-zero.
Likelihood:
A threat actor can intentionally exploit this. They can observe large stakes on-chain and send a minimal poison deposit to the victim's address, overwriting the victim's large stakedAsset balance with a near-zero amount.
The vulnerability is also triggered by an accidental, non-malicious user action. If User A wants to deposit for User B who already has a balance, User A's new deposit will overwrite User B's entire existing stake instead of adding to it, leading to an unexpected and catastrophic loss of funds for User B.
Impact:
When the victim calls cancelParticipation, they are only refunded the attacker's tiny dust amount. However, the function proceeds to burn the victim's entire share balance.
The victim's original, large stake is now orphaned and remains in the vault. These orphaned funds are no longer associated with the victim's burned shares. This massively increases the value of all remaining shares, which includes the shares the attacker minted from their poison deposit. The attacker can then redeem their shares to claim all the funds the victim lost.
This test demonstrates the attack in three steps.
Victim Deposit user1 (the victim) deposits 5 ether. stakedAsset[user1] is set to ~5 ether.
Attacker Overwrite user2 (the attacker) calls deposit with a minimal amount (0.000204 ether) but specifies user1 as the receiver. This overwrites stakedAsset[user1] to this new, tiny value.
user1 calls cancelParticipation. The function reads the overwritten, near-zero stakedAsset balance and refunds only that amount. The victim's original 5 (minus fee) ether is now trapped in the contract.
This mitigation applies two fixes:
stakedAsset[receiver] += stakeAsset.
This is the primary security fix. It changes the assignment (=) to an addition (+=), preventing an attacker from overwriting a victim's balance. Deposits are now correctly accumulated.
_mint(receiver, participantShares)
This is a logical correction. It ensures that the receiver also receives the shares representing that stake, rather than the msg.sender'.
Vault tracks only a single deposit slot per user and overwrites it on every call instead of accumulating the total.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.