Open code423n4 opened 2 years ago
The warden identified a way to sidestep the accounting in the ConvexYieldWrapper
.
Because ConvexYieldWrapper
takes lazy accounting, transferring vaults at the Ladle
level allows to effectively register the same vault under multiple accounts, which ultimately allow to steal more yield than expected.
While the loss of yield can be classified as a medium severity, the fact that the warden was able to break the accounting invariants of the ConvexYieldWrapper
leads me to raise the severity to high
Ultimately mitigation will require to _checkpoint
also when vault operations happen (especially transfer), this may require a rethinking at the Ladle level as the reason why the warden was able to sidestep the checkpoint is because the Ladle
doesn't notify the Wrapper
of any vault transfers
Yes, that's right. To fix this issue we will deploy a separate Ladle to deal specifically with convex tokens. The fix will probably involve removing stir
and give
instead of notifying the wrapper, but we'll see.
Handle
leastwood
Vulnerability details
Impact
ConvexYieldWrapper.sol
is a wrapper contract for staking convex tokens on the user's behalf, allowing them to earn rewards on their deposit. Users will interact with theLadle.sol
contract'sbatch()
function which:ConvexYieldWrapper.sol
.Ladle.sol
._getDepositedBalance()
takes into consideration the user's total collateral stored in all of their owned vaults. However, as a vault owner, you are allowed to give the vault to another user, move collateral between vaults and add/remove collateral. Therefore, it is possible to manipulate the result of this function by checkpointing one user's balance at a given time, transferring ownership to another user and then create a new checkpoint with this user.As a result, a user is able to generate protocol yield multiple times over on a single collateral amount. This can be abused to effectively extract all protocol yield.
Proof of Concept
Consider the following exploit scenario:
_getDepositedBalance()
returns 100 as its result. A checkpoint has also been made on this balance, giving Alice claim to her fair share of the rewards.Ladle.give()
, transferring the ownership of the vault to Bob and callsConvexYieldWrapper.addVault()
.user_checkpoint()
and effectively update their checkpointed balance.https://github.com/code-423n4/2022-01-yield/blob/main/contracts/ConvexYieldWrapper.sol#L100-L120
Tools Used
Manual code review. Discussion/confirmation with the Yield Protocol team.
Recommended Mitigation Steps
Ensure that any change to a vault will correctly checkpoint the previous and new vault owner. The affected actions include but are not limited to; transferring ownership of a vault to a new account, transferring collateral to another vault and adding/removing collateral to/from a vault.