Let's take a look at how the distribution of awards to DAO participants works. Specifically, what rewards a user receives when joining.
User's rewards are updated when the saveProfit function is called.
When a user joins Dao, the order of calling internal functions is as follows:
1)saveProfit
2)_update
That is, the user's NFT balances are updated after their reward has been calculated. I.e. at the moment when the rewards are calculated in saveProfit shareOf(user) = 0 => saved = 0, but lastProfit will be updated to the current totalProfit.
In short, the user only gets his rewards for the sendProfit called after the user joins DAO, and does not get rewards for the total Profit distributed before that.
This opens up the possibility of sandwiching the first sendProfit from any person if there are no members in the DAO yet (which is very likely, since it costs money to join the DAO and no Profit yet). In order to take the entire first sendProfit - he would need the following sequence of transactions.
mint at least 1 share
send profit
Then he can call claimProfit at any time - the whole first sendProfit will be his.
In my opinion, the root cause of this problem is a slightly inefficient system of award distribution. This system strictly depends on the order in which transactions are called, which can be easily manipulated. Thus, a large share holder will not receive any rewards until the next sendProfit after his mint is called, while a participant with 1 share will receive the entire first sendProfit.
Since the protocol allows frontrunning send profit, as stated in the H-01 Cyfrin Audit Report - it needs to at least defend against the first deposit attack.
I would like to emphasise the difference between this error and the error described in H-01. Error H-01 talks about frontrunning in general case and manipulation of profit, but not full loss of it and suggests as mitigation to add delay on reward distribution when joining DAO.
This error also uses sendProfit frontrunning, but speaks about the specific case of the first sendProfit frontrunning when the number of DAO shares = 0 (totalSupply = 0)
In this case, the intended behaviour of the protocol is to send the entire sendProfit to the creator address. However, because of the frontrunning, all profit will go to the first depositor, regardless of his number of shares >= 1.
Since the attack is very easy to execute, doesn't cost much and can result in a significant loss of funds - high
Manual Review
As is done in many contracts like ERC4626 - add protection against first depositor attack. The easiest way to do it is to print fictitious shares (just initialise totalSupply not with 0 number, but conditionally with 10). In this case the attacker will get not the whole profit, but only profit / 10.
Also, if we are talking about a more global change - you can change the reward distribution system to Masterchef Staking Algorithm - it will take into account time-weighted contribution of each user to DAO.
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.