In current implementation, Voter.distribute is used to distribute ALCX among gauges, during the call there is an issue that a malicious user can back-run Voter.distribute to steal reards.
Vulnerability Details
During the Voter.distribute function, Voter._distribute is called, and at the end of Voter._distribute, IBribe.resetVoting is called at [https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/Voter.sol#L377] IBribe.resetVoting is defined as:
During Voter.distribute, Bribe.totalVoting will be set to 0
Bribe.earned depends of Bribe.totalVoting to calculate the amount of rewards. And if we can force _priorSupply to 1 while calculating the rewards, we will make more profilt. We can use Voter.poke to update the checkpoint after Voter.distribute.
Impact Details
In current implementation, Voter.distribute is used to distribute ALCX among gauges, during the call there is an issue that a malicious user can back-run Voter.distribute to steal reards.
References
Add any relevant links to documentation or code
Proof of Concept
put the follow code in src/test/Voting.t.sol and run
FOUNDRY_PROFILE=default forge test --fork-url https://eth-mainnet.alchemyapi.io/v2/$API_KEY --fork-block-number 17133822 --mc VotingTest --mt testAliceEpochRewards -vv
[⠊] Compiling...
No files changed, compilation skipped
Ran 2 tests for src/test/Voting.t.sol:VotingTest
[PASS] testAliceEpochRewardsNoPoke() (gas: 6888013)
Logs:
earned : 33333333333333333333333
earned : 33333333333333333333333
bal.balanceOf(Alice) : 33333333333333333333333
bal.balanceOf(Bob) : 0
[PASS] testAliceEpochRewardsPoke() (gas: 6969463)
Logs:
earned : 100000000000000000000000
earned : 100000000000000000000000
bal.balanceOf(Alice) : 100000000000000000000000
bal.balanceOf(Bob) : 0
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 86.68ms (116.98ms CPU time)
As we can from above, if Alice doesn't call Voter.poke after Voter.distribute, Alice will receive 33333333333333333333333 bal rewards.
And if Alice calls Voter.poke after Voter.distribute, Alice will receive 100000000000000000000000 bal rewards.