BriVault

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

cancelParticipation() allows withdrawal of full deposit without accounting for participation fee

Root + Impact

Description

  • Normal behavior:
    Users should be able to cancel participation before the event starts, but the contract should deduct any participation fee already charged.


  • Specific issue:
    In cancelParticipation():

  • The refund ignores the participation fee that was transferred to participationFeeAddress during deposit().

Users can effectively bypass fees, leading to fee loss for the event organizers.

  • No check prevents double cancel if called repeatedly, though _burn() partially mitigates this.

// Root cause in the codebase with @> marks to highlight the relevant section
@> uint256 refundAmount = stakedAsset[msg.sender];
@> stakedAsset[msg.sender] = 0;
@> _burn(msg.sender, shares);
@> IERC20(asset()).safeTransfer(msg.sender, refundAmount);

Risk

Likelihood:

  • This occurs whenever a user deposits and cancels before eventStartDate, since the refund ignores the fee.

This occurs if a user deposits and then immediately cancels, or exploits multiple deposit-cancel cycles.

Impact:

  • Loss of intended participation fee revenue.

Could incentivize users to deposit and immediately cancel multiple times to game rewards vs. fees.

Proof of Concept

Explanation:

  • The user receives full staked amount, even though a portion should have been charged as participation fee.

  • Repeating this process could circumvent fee collection entirely.


contract CancelFeeBypass {
function exploit(BriVault vault, uint256 amount) external {
vault.deposit(amount, msg.sender);
vault.cancelParticipation(); // full amount refunded, fee bypassed
}
}

Recommended Mitigation

Brief explanation:

  • Deduct the participation fee from the refund in cancelParticipation().

  • Ensure refund is only the staked portion:

- remove this code
+ add this code
- uint256 refundAmount = stakedAsset[msg.sender];
+ uint256 refundAmount = stakedAsset[msg.sender]; // already net of fee
Updates

Appeal created

bube Lead Judge 20 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!