Vulnerability disclosure 2022-11-01
- During a routine check, irregularities were discovered in the amount of SPELL bribes being claimed by some users of the BribeV2 contract. Following analysis, it was determined to be an attacker exploiting a flaw in the way the contract calculates bribe allocations.
- The flaw causes bribes to be allocated based on each user's locked amount of CRV rather than allocating based on their veCRV balance.
- The attacker was found to have exploited this since September 2021, tricking the contract into awarding them higher allocations than they should deserve for the actual weight they contributed to a gauge.
- Other BribeV2 users were unknowingly subject to faulty bribe calculations due to the fact that lock time was not taken into account.
- Yearn developers patched the vulnerability and deployed a new version of the contract (yBribe) which properly allocates bribes to users.*
Disclaimer: The Yearn team did not write or deploy the original BribeV2 contract. However, as a heavy user of it, decided to act quickly to deploy a new contract so that operations could resume.
Curve Finance have pioneered a now popular tokenomics system known as veCRV which allows users to lock tokens for up to 4 years with a balance that decays every block until the lock expires or is extended. As their veCRV balance decays, so does their relative influence over Curve governance, including gauge voting.
The BribeV2 contract was released as a trustless mechanism for entities (usually protocols) to incentivize veCRV voters to cast votes for their desired gauge, increasing the amount of CRV emissions to that gauge. A briber would simply deposit tokens into BribeV2, and the contract reads from Curve's Gauge Controller to calculate token allocations for each voter according to their global influence on the gauge weights.
Importantly, gauge weights are determined not by a user's locked amount, but by their veCRV balance which is a time-based decayed representation of their locked amount.
Whilst preparing an internal report for Yearn's Curve Voting + Bribes committee, Yearn devs discovered irregularities in the amount of SPELL bribes being claimed each week from BribeV2.
Details of vulnerability
The source of the irregularities had to do with BribeV2 utilizing the slope value for users and gauges in the Gauge Controller rather than bias value .
A user's slope value in the veCRV system is a representation of the decay rate per second on their locked amount, but completely ignores their lock duration. This is a critical flaw because it allows someone with a short lock to get paid out at an equal rate to someone with a long lock on the same amount. Crucially, this method does not match how the Gauge Controller assigns gauge weights, which does indeed take lock time into account.
This issue can lead to the following exploit:
- The numbers used by BribeV2 are stale. Only up-to-date from the last time the claimer voted. A claimer can withdraw all of their veCRV after voting and BribeV2 won’t know.
- BribeV2 checks voting power based on how much is locked rather than what the voting balance is. A user locking for one week will get the same share as a user locking for 4 years.
BribeV2 incorrectly uses a user's slope (which is determined by the amount of CRV they lock). As a part of this report, Yearn devs produced a detailed comparison of slope and bias.
The combination of the two means there is an exploit where a user can:
- Lock 1m CRV for the minimum amount of time (7 days)
- Vote for a gauge with a veCRV balance of 4,808 (1m CRV / 208 weeks) but claim rewards based on a gauge vote of 1m veCRV.
- Withdraw 1m CRV as soon as possible
- Continue to claim rewards every week forever
Because the CRV can be withdrawn after a week, an exploiter can cycle the same CRV through multiple wallets getting perpetual rewards forever on each, as can be seen in this proof of concept of the exploit.
Source : github.com/yearn/yearn-security/blob/master/disclosures/2022-11-01.md undefined - November 15, 2022