Users must pay a participation fee on deposited assets before joining the event. Larger deposits incur proportionally larger fees. After funding, users call briVault::joinEvent() to be added to the competition.
However, there is a critical gap: joinEvent() snapshots the current ERC4626 share balance via balanceOf(msg.sender), while the protocol’s fee logic only runs inside deposit(). Because ERC4626 mint() is not overridden, a user can:
make a tiny fee-paid deposit (to pass minimumAmount + fee),
Then call mint() to acquire the rest of their shares without paying a participation fee,
and finally call joinEvent() — which snapshots the fee-bypassed balance.
This lets users join with a large share weight while paying only a tiny fee.
Additionally, this open mint function can do numerous harms. For example, it lets anyone mint shares even after the event gets started, thus breaking one of the invariants.
Likelihood: High
mint() is publicly callable and ungated; no preconditions beyond ERC20 allowance.
Economically attractive: pay a minimal fee, capture a maximal snapshot.
Impact: High
First, the protocol loses a lot of fees when every user attempts such a thing.
Second, the open mint function can break several core invariants, and thus proves to be risky. Well, it ain't a DeFi protocol where one mints shares whenever they want.
Here's how the exploit unfolds:
Setup:
Two users: user1 (the exploiter), and user2 (our naive lad)
Both want to spend 5 tokens of their asset, and select the countryId as 10
The Exploit:
user1 deposits with a minimal amount, just above the minimumAmount required by deposit. As the amount was minimal, the fees will be low.
user2 deposits all 5 tokens and gets his shares, paying higher fees than user1. Later, he calls joinEvent.
user1 mints himself shares by using the mint function by depositing the rest of the (5 - minimal Amount) tokens left. Paying no fees for it.
After that, user1 calls the joinEvent function that considers his current share balance, i.e. 5 shares.
Well demonstrated in the PoC, using comments...
Add this test_bypassingFeesUsingMint test in briVault.t.sol, along with the helper function _getParticipationFees:
One can use the following command to run the test:
Logs:
There are several fixes that the protocol can make in order to mitigate this issue.:
Recommended: Disable the mint() function completely. In other words, make mint() unavailable as an entry point for users (force them to use deposit() only). With this, no one will be able to mint shares whenever they want.
Or, if you want to allow mint, then make it behave like deposit(), i.e. apply fees, and enforce minimumAmount, eventStartDate, etc.
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.