-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sole depositor in the VotiumStrategy
contract can inflate cvxPerVotium()
to steal subsequent deposits
#26
Comments
nice examples of the problem. @toshiSat I think the easiest solution is to just do a seed deposit so we dont have to worry about or analyze any math/contract changes |
Yes, the plan is to do a seed deposit with the multisig once launched |
0xleastwood marked the issue as primary issue |
0xleastwood marked the issue as duplicate of #35 |
0xleastwood marked the issue as satisfactory |
0xleastwood changed the severity to 2 (Med Risk) |
0xleastwood changed the severity to QA (Quality Assurance) |
This previously downgraded issue has been upgraded by 0xleastwood |
0xleastwood marked the issue as not a duplicate |
0xleastwood changed the severity to QA (Quality Assurance) |
This previously downgraded issue has been upgraded by 0xleastwood |
1 similar comment
This previously downgraded issue has been upgraded by 0xleastwood |
0xleastwood marked the issue as duplicate of #35 |
Lines of code
https://github.com/code-423n4/2023-09-asymmetry/blob/main/contracts/strategies/votium/VotiumStrategy.sol#L39-L46
Vulnerability details
Bug Description
In
VotiumStrategyCore.sol
, thecvxInSystem()
function returns the total amount of CVX in the protocol:VotiumStrategyCore.sol#L133-L138
The total amount of CVX is sum of the amount of locked CVX and the contract's current CVX balance. An attacker can "donate" CVX to the protocol to cause
cvxInSystem()
to increase by doing either of the following:VotiumStrategy
contract.depositRewards()
with ETH, which will exchange ETH for CVX and hold it in the contract.cvxInSystem()
is called bycvxPerVotium()
to determine the amount of CVX per vAfEth:VotiumStrategyCore.sol#L144-L149
Where:
cvxUnlockObligations
is the amount of CVX for pending withdrawals.As seen from above,
cvxPerVotium()
is essentially calculated fromcvxInSystem()
divided by the total supply of vAfEth. Therefore, ifcvxInSystem()
increases,cvxPerVotium()
will also increase proportionally.This becomes problematic as
cvxPerVotium()
is used to determine the amount of vAfEth to mint to the depositor whendeposit()
is called:VotiumStrategy.sol#L39-L46
The amount of vAfEth to mint is determined by the caller's deposit (
cvxAmount
) is divided bycvxPerVotium()
.However, when the total supply of vAfEth is extremely small, an attacker can artificially inflate
cxvPerVotium()
by "donating" a huge amount of CVX to the protocol. IfpriceBefore
becomes sufficiently large,cvxAmount * 1e18 / priceBefore
will round down to 0, causing subsequent depositors to receive 0 vAfEth.Impact
When the total supply of the
VotiumStrategy
contract is extremely small, an attacker can forcemintAmount
to round down to 0 indeposit()
, thereby minting 0 vAfEth to subsequent depositors. This will cause all future deposits to accrue to the attacker's vAfEth, leading to a theft of funds from future depositors.Proof of Concept
Assume that the
VotiumStrategy
contract is newly deployed and has no depositors yet.Alice calls
deposit()
with an extremely smallmsg.value
:buyCvx()
returnscvxAmount = 1
.cvxPerVotium()
is1e18
.Alice directly transfers 1000 CVX to the contract. Now, if
cvxPerVotium()
is called:totalSupply() = 1
cvxInSystem() = 1000e18
cvxUnlockObligations = 0
1e36
as:Bob calls
deposit()
with ETH worth 500 CVX:buyCvx()
returnscvxAmount = 500e18
cvxPerVotium()
returns1e39
.mintAmount
will round down to 0 as:In this scenario,
mintAmount
will always round down to 0 if Bob deposits less than 1000 CVX worth of ETH. All of the CVX deposited by Bob accrues to Alice's 1 vAfEth, resulting in a loss of funds for Bob.Note that another possible way for
totalSupply()
to become 1 is if everyone withdraws and Alice happens to be the last depositor in theVotiumStrategy
contract. She can then withdraw all her vAfEth except 1 by callingrequestWithdraw()
andwithdraw()
.Recommended Mitigation
In
deposit()
, consider mintingx
amount of vAfEth to a dead address whentotalSupply() == 0
:This ensures that
totalSupply()
will never be low enough for an attacker to inflatecvxPerVotium()
significantly.Assessed type
DoS
The text was updated successfully, but these errors were encountered: