Summary
The _rebalanceLiquidity function deposits assets into Curve Vault with address(this) as the owner, but tries to withdraw them with msg.sender as the owner. This fails because msg.sender doesn’t own the shares.
Vulnerability Details
In _depositIntoVault, the contract calls curveVault.deposit(amount, address(this)), making the lending pool (address(this)) the owner of the minted shares. Later, in _withdrawFromVault, it calls curveVault.withdraw(amount, address(this), msg.sender, 0, []), telling Curve Vault to burn shares owned by msg.sender. But msg.sender (the user calling deposit) never received shares—address(this) did. Curve Vault’s withdraw function checks the owner and reverts because msg.sender has no shares to burn. For example:
User deposits 100 crvUSD.
_rebalanceLiquidity moves 50 crvUSD to Curve Vault, owner = address(this).
Later, it tries to withdraw 20 crvUSD, claiming msg.sender as owner, but fails.
LendingPool._withdrawFromVault
Impact
Withdrawals from Curve Vault fail during rebalancing, leaving liquidity stuck. Users can deposit, but the pool can’t pull funds back when needed, breaking borrowing or withdrawal functions that rely on _ensureLiquidity. This locks up assets and disrupts the system.
Tools Used
Manual review of deposit, _rebalanceLiquidity, _depositIntoVault, _withdrawFromVault, and Curve Vault’s deposit/withdraw functions.
Recommendations
Fix Owner in Withdraw: Use address(this) as the owner in _withdrawFromVault since it owns the shares.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.