BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

User with two addresses can participate for free in the tournament

Root + Impact

Description

The vault allows users to transfer their ERC-4626 shares freely at any time, and also provides a cancelParticipation() function that refunds a user’s full stakedAsset[msg.sender] amount while burning only their current share balance.

Because the cancelParticipation() refund logic depends on stakedAsset[msg.sender] (which is not adjusted when the user transfers shares), an attacker can exploit this by transferring their shares to another address (already joined an event) before requesting a refund.

Impact: The second address participate with free shares on the tournament

function cancelParticipation () public {
if (block.timestamp >= eventStartDate){
revert eventStarted();
}
@> uint256 refundAmount = stakedAsset[msg.sender];
stakedAsset[msg.sender] = 0;
@> uint256 shares = balanceOf(msg.sender);
@> _burn(msg.sender, shares);
@> IERC20(asset()).safeTransfer(msg.sender, refundAmount);
}

Risk

Likelihood: High

  • The exploit is trivial: only standard ERC-20 transfer() and ERC-4626 redeem() calls are required. No timing or complex setup is needed.

Impact:

  • User with two addresses can participate for free in the tournament

Proof of Concept

Setup:

  1. Wallet2 deposits small amount and joins team

  2. Attacker deposits 100 ETH → gets 98.5 shares

  3. Attacker transfers 98.5 shares to wallet2

  4. Attacker calls cancelParticipation() → gets 98.5 ETH refund

  5. Wallet2 uses free shares in the tournament

  6. Event ends

  7. Wallet2 withdraws if it's on the winner team (but anyway it partecipated with free shares)

This can be repeated with many addresses to increase chanse of win and to take the final profit.

Recommended Mitigation

Make shares non-transferable until after event, by overriding _update function.

function _update(address from, address to, uint256 value) internal override {
if (from != address(0) && to != address(0)) {
if (block.timestamp < eventEndDate) {
revert("Shares locked during event period");
}
}
super._update(from, to, value);
}
Updates

Appeal created

bube Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

Unrestricted ERC4626 functions

Support

FAQs

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

Give us feedback!