31085 - [SC - Critical] Malicious users can front-run the distribution ...

Submitted on May 12th 2024 at 14:17:54 UTC by @Ch301 for Boost | Alchemix

Report ID: #31085

Report type: Smart Contract

Report severity: Critical

Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/Voter.sol

Impacts:

  • Theft of unclaimed royalties

Description

Brief/Intro

The pool weight is zero but users are still able to claim bribes.

Vulnerability Details

First, let's understand two main points:

1- When a user invokes Voter.sol#vote()[#1] will update lastVoted[_tokenId] to block.timestamp

File: Voter.sol

508:         lastVoted[_tokenId] = block.timestamp;

Users to be able to reset the voting status, need to call Voter.sol#reset(). However, the modifier onlyNewEpoch() will force the user to wait until a new epoch starts since the last vote. So user can call reset() at the first second of the new epoch.

2- To distribute rewards and bribes to all gauges you need to call Voter.sol#distribute() only once per epoch. (Normally this is done by off-chain bots)

Now, the first point updates all the related values, but the Bribe.sol#withdraw() will create a new checkpoint X (see: _writeCheckpoint()[#2]) this checkpoint get considered for the new epoch not the last epoch.

Next time the user calls voter.sol#claimBribes(). the balanceOf of the epoch X - 1 will allow the user to claim all/part from the bribes even if he didn't help the gauge to generate more emrssions

Impact Details

1- If the malicious user is the only one who votes to a gauge, He will claim all the bribes if they exist and the pool will receive zero emissions.

2- If there are multiple users vote for that particular pool, the malicious user will steal a part from other user's bribes.

References

#1: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/Voter.sol#L449

#2: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/Bribe.sol?utm_source=immunefi#L351-L360

Proof of Concept

Foundry PoC:

  1. Please copy the following PoC in Voting.t.sol

  1. Test result:

Last updated

Was this helpful?