BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Refund without burning corresponding shares (transfer-then-cancel) → free cash + unbacked shares

Root + Impact

Description

  • Normal behavior: cancelParticipation() should only refund value corresponding to shares that are burned.

  • Issue: The function refunds stakedAsset[msg.sender] regardless of current share balance; an attacker can transfer all shares away, then cancel and get a full refund while burning 0 shares.

function cancelParticipation() public {
if (block.timestamp >= eventStartDate){ revert eventStarted(); }
uint256 refundAmount = @> stakedAsset[msg.sender]; // refund based on stale state
@> stakedAsset[msg.sender] = 0;
uint256 shares = balanceOf(msg.sender); // could be 0 after transferring away
@> _burn(msg.sender, shares); // burns 0 shares
@> IERC20(asset()).safeTransfer(msg.sender, refundAmount); // full cash-out
}

Risk

Likelihood:

  • Occurs whenever a depositor transfers shares to another address and then calls cancel.

  • No restrictions on transfers prior to cancellation.

Impact:

  • Direct theft: cash refund is paid while the corresponding shares still exist elsewhere.

  • At event end, those unbacked shares can claim winnings → double drain.

Proof of Concept

Attacker deposits to get shares in address A.
Transfers all shares from A to B.
Calls A.cancelParticipation() → receives full refund; 0 shares are burned.
Later, B keeps/use shares to withdraw a prize.

Recommended Mitigation

- remove this code
+ add this code
Updates

Appeal created

bube Lead Judge 21 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!