Computing bountyEntitlement with snapshotTotalStaked + snapshotTotalBonus silently failed to capture the full balance of the pool, as the attacker's bounty, leading to the attacker missing out on some of their bounty to the recovery address
The expected behavior is that if the agreement is corrupted in goodFaith then the moderator passes in the boolean goodFaith_ as true and passes in the address of the whitehat attacker that corrupted the agreement, making the attacker eligible for the total balance of the pool as their bounty from the resolution moment till corruptedClaimDeadlineas specified by the DESIGN.md
Unfortunately, because the protocol developers used snapshotTotalStaked + snapshotTotalBonus to compute bountyEntitlement, which is assumed to be the total balance of the pool, which is to be awarded to the whitehat attacker, they silently failed to capture the full balance of the pool, because it is very likely that a user may donate bonus to the pool by sending tokens directly to the pool instead of calling the contributeBonus function. That excess bonus that was sent directly to the pool without calling the contributeBonus function would be swept to the recoveryAddress later, which breaks the core design of the protocol, which states that there is no separate "surplus" alongside an unclaimed bounty in the normal case
Let's walk through your possible argument and my response to it:
Your argument: This is a design choice, it is intended by the protocol
My response: This does not make any sense, and it was not intended by the protocol because I carefully read through the DESIGN.mdand it was never mentioned for once, which makes it clear the protocol dev never thought of it or even saw it coming. Instead, they give plenty of evidence, making it clear that the whole pool balance and not (snapshotTotalStaked + snapshotTotalBonus), which they foresee as the pool's whole balance, which excludes some of the balance of the pool, is supposed to go to the whitehat attacker.
I am not talking from my feelings, but strictly on the design of the protocol. Now, look at the below said in ##12 of DESIGN.md
The above makes it clear that only the bonus that lands after the total balance of the pool at the time of resolution has been awarded to the whitehat attacker is to be swept to the recoveryAddress and not any other bonus before the pool resolution time
Since bountyEntitlement and corruptedReserve hold the same value, this vulnerability affects them both, and the mitigation recommended below should be applied to both.
Likelihood:
This will happen when anyone contributes a bonus to the pool without directly calling the contributeBonus function, and a whiteHat corrupts the agreement the pool is backing.
Impact:
The whitehat would lose out on some of their bounty to the reserveAddress
Put the code below in test/unit/ConfidencePool.k2Bonus.t.sol and run the test with forge test --mt testBountyDoesNotCaptureDirectDonationsSilentlyCuttingDownAttackerBounty
corruptedReserve only goes down, and bountyEntitlement stays as it is to be compared against bountyClaimed to be able to determine if the attacker has successfully claimed all their bounty, so these changes have no side effects
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.
The contest is complete and the rewards are being distributed.