-
Notifications
You must be signed in to change notification settings - Fork 0
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
Security Review Report #19
Comments
Perhaps we could ask the other auditors as well if they consider it as an issue. If an issue cannot be identified I could add it in the |
You can add these in additional notes section. We have no plan of enabling flashloans on vyToken so not testing/fixing this for now. |
@DecorativePineapple : Point 2 has been addressed in #21 |
Regarding the rounding attack on If the victim's deposit is very large with regards to the contract assets, this would be significant. A zero check is quite limited in its protection, as the attacker could then modify the attack so that the user gets exactly 1 share. We have implemented a system for general transaction checks that offers better protection. We will include vyToken transactions in a batch with a call at the end that verifies that the user received a number of tokens within slippage settings. https://github.com/yieldprotocol/yield-utils-v2/blob/main/src/utils/Assert.sol |
Regarding the issue with the interest rate oracle not being updated more than once in a block, we will fix that at the root, by removing the maximum update per block constraint. |
Yield VR Security Review
A security review of the Yield Variable Rate smart contract protocol was done by Christos Pap.
This security review report includes all the vulnerabilities, issues and code improvements found during the security review.
Disclaimer
"Audits are a time, resource and expertise bound effort where trained experts evaluate smart
contracts using a combination of automated and manual techniques to find as many vulnerabilities
as possible. Audits can show the presence of vulnerabilities but not their absence."
- Secureum
About Christos
Christos Pap is an independent security researcher who specializes in Ethereum smart contract security. He currently works as a Junior Security Researcher at Spearbit and is an alumnus of the yAcademy fellowship program. Additionally, he is undergraduate student of Electrical and Computer Engineering and he has extensive experience in offensive security, having worked as a Penetration Tester and holding the OSCP certification. You can connect with him on Twitter at @christos_eth.
Risk classification
Impact
Likelihood
Actions required by severity level
Executive summary
Overview
Issues found
Scope
Findings
VariableInterestRateOracle:get
function affects the interest rate of theYield Variable Rate
ProtocolName
,Symbol
andDecimals
will have the default values in theVyToken
Yield Variable Rate Protocol
, including liquidations, can be frozenEIP3156
standard may affect composabilityRedeemed
event to be emitted with the wrongholder
argumentTransferHelper
library does not verify token code size before executing transfersHigh severity
[H-01] Precision loss in the
VariableInterestRateOracle:get
function affects the interest rate of the Yield Variable Rate ProtocolContext: VariableInterestRateOracle.sol#L200-L204, VariableInterestRateOracle.sol#L206-L212, VariableInterestRateOracle.sol#L194-L196
Description: The interest rate calculation formula used in the code is based on the formula used by AAVE.
If
utilizationRate <= rateParameters.optimalUsageRate
, the interest rate is calculated as:However, since
wmul
andwdiv
function are used together, the calculation is performed as follows:interestRate = rateParameters + utilizationRate * rateParameters.slope1 / 1e18 * 1e18 / rateParameters.optimalUsageRate
.This leads to precision loss, since a division (
/ 1e18
) is performed before the multiplication (* 1e18
).A similar issue occurs also when
utilizationRate > rateParameters.optimalUsageRate
.Recommended Mitigation Steps: To avoid precision loss in the
get
function, it is recommended to adjust the calculations as follows:interestRate = rateParameters.baseVariableBorrowRate + utilizationRate * rateParameters.slope1 / rateParameters.optimalUsageRate;
Yield Team: We have now removed the usage of the
wmul
andwdiv
functions.Christos Pap: Verified.
[H-02] Inaccurate refund logic causes incorrect accounting in underlying Join contract
Context: VRLadle.sol#L381, Join.sol#L44
Description: The
repay
function in theVRLadle
contract can be used by a user to repay all the debt in a vault. According to the function comments, the surplus base will be returned tomsg.sender
.However, the refund logic in the
repay
function is flawed. The user is refunded while thestoredBalance
from the underlyingJoin
is reduced, leading to broken accounting in theJoin
contract because thestoredBalance
will get smaller when the surplus funds are refunded.An attacker could potentially exploit this issue by sending a large amount to the Join contract, then calling the repay function, causing the storedBalance to decrease significantly.
The
exit
function of theJoin
contract:Recommended Mitigation Steps: To address this issue, it is recommended to add a new function to the Join contract that retrieves the unaccounted amount. This function should be called instead of the
exit
function to ensure that the correct accounting is maintained.Yield Team: Good catch. I think the Join needs a skim function that allows to take the difference between the actual balance and the stored balance, similar to this.
We fixed it by introducing a
skim
function in theJoin
smart contract.Christos Pap: Verified.
Medium severity
[M-01]
Name
,Symbol
andDecimals
will have the default values in theVyToken
Context: VYToken.sol#L41
Description: The yield-utils-v2 ERC20 implementation does not declare the decimals, string, and symbol as immutables. As the
VYToken
contract is intended to be upgradeable, the constructor code of the ERC20 implementation will not be executed during initialization, resulting in default values. Consequently,VYToken
has 0 decimals, which differs from the underlying token.Due to a requirement of the proxy-based upgradeability system, no
constructors
can be used in upgradeable contracts. Immutable will work, since they aren't stored in the storage, and the compiler will place them into the bytecode in the deployment.If we ran the following snippet we can see that the
VYToken
has0
decimals, which is different than the intended behaviour.Recommended Mitigation Steps: It is recommended to also mark the decimals, string, and symbol as immutables in the yield-utils-v2 ERC20 token. Alternatively, the
initialize
function could be used to set those values.Yield Team: Fixed by using the
initialize()
function to set the decimals, string, and symbol variables.Christos Pap: Verified.
Low severity
[L-01] If the spot oracle goes down, most of the
Yield Variable Rate Protocol
, including liquidations, can be frozenSeverity: Low
Context: VRCauldron.sol#L139, ChainlinkMultiOracle.sol#L16
Description: The
setSpotOracle
function in theVRCauldron
contract sets an instance of theChainlinkMultiOracle
contract contract as theIOracle
. However, theChainlinkMultiOracle
contract uses a single oracle to obtain the latest price feed.According to OpenZeppelin's Smart Contract Security Guidelines #3: The Dangers of Price Oracles,
Chainlink has taken oracles offline in extreme cases, such as during the UST collapse when it paused the UST/ETH price oracle to prevent protocols from receiving inaccurate data.
Recommended Mitigation Steps: To protect against the possibility of access to Chainlink feeds being denied, it is recommended to implement a safeguard such as a fallback oracle or an alternative approach that can act when needed.
Yield Team: In extreme cases a proposal could be executed to change the
spotOracle
. Since it is a risk in an extreme case we would stick with the current mitigation methodology.Christos Pap: Aknowledged.
[L-02] Deviation from
EIP3156
standard may affect composabilityContext: VYToken.sol#L248, VYToken.sol#L181-L195
Description:
VYToken
isn't fully compatible with theEIP3156
standard.According to the
Lender Specification
, it's noted that:However, due to the custom
_burn
function in theVYToken
contract, the amount is taken from the contract instead, if there are some funds inside it.Recommended Mitigation Steps: To make the
VYToken
contract fully compatible with the EIP3156 standard, it is recommended to remove the custom_burn
function and to modify theVYToken
accordingly.Yield Team: Hi, you are right, this is a deviation from the standard as written. However, when I wrote it I intended that this would be allowed (same as is in 4626).
Meaning that if the borrower approves the repayment, that should always work. However, if the lender also has an alternative repayment method and the borrower decides to use it, there should be no impediment.
Thanks for raising it, I'll revise the wording in 3156 instead of changing the code here.
Christos Pap: Verified.
[L-03] An attacker can force the Redeemed event to be emitted with the wrong holder argument
Context: VYToken.sol#L111, VYToken.sol#L143
Description: The custom
_burn
function allows a user to transfervyToken
to the contract to enable aburn
, potentially saving the cost ofapprove
orpermit
. This is achieved by using any tokens that are present in theVyToken
contract.However, this functionality can be exploited by an attacker because the
withdraw
andredeem
functions in the contract allow a user to input aholder
address as an argument. An attacker can send tokens directly to the contract and then pass any address as the holder argument in thewithdraw
/redeem
function, which forces that address to be emitted at theRedeemed
event.Recommended Mitigation Steps: It is difficult to mitigate this issue with the current setup. A possible solution could be to check the approval in the
withdaw
/redeem
function.Yield Team: Our users are instructed to strictly use the frontend. So, we are not going to change this.
Christos Pap: Acknowledged.
Informational
[i-01] No allowance front-running mitigation
Context: VYToken.sol#L16
Description: The
VYToken
contract is inherited fromERC20Permit
, which, in turn, is inherited from theERC20
contract. These contracts are part of theyield-utils-v2
GitHub repository.None of these contracts provide protection against the
allowance front-running attack
. This attack can occur when a token owner authorizes another account to transfer a specific amount of tokens on their behalf. If the token owner decides to change the allowance amount, the spender can spend both allowances by front-running the allowance-changing transaction.Recommendation To mitigate this issue, you could consider using the
OpenZeppelin ERC20
implementation. This implementation includes the increaseAllowance and decreaseAllowance functions, which protect against the allowance front-running attack. Although an attacker may not have any incentive to perform this attack, adding these functions can be seen as an added layer of protection.[i-02]
TransferHelper
library does not verify token code size before executing transfersContext: TransferHelper.sol
Description: The
TransferHelper
library fails to verify whether a token has code before executing a token transfer. Consequently, if the token address is empty, the transfer will succeed without crediting the contract with any tokens. While the tokens added to the VRLadle are whitelisted, this can still disrupt internal accounting in the following ways:.transferFrom
and.transfer
will succeed, breaking the internal accounting.Yield Variable Rate
is deployed on multiple chains, such as onMainnet
and onArbitrum
, and an admin mistakenly adds a token toArbitrum
that does not exist only exists on Mainnet, it could create an opportunity for a honeypot attack similar to theQubit Finance hack
.Recommended Mitigation Steps: To mitigate this issue, it is recommended to check if the contract has code before executing
.transfer
and.transferFrom
functions. OpenZeppelin'sSafeERC20
library verifies this condition here and can be used as a reference.Yield Team:
The same and worse effects can happen if one of the tokens is upgraded, which is the same kind of attack vector but is much more likely.
With regards to all governance errors, we prefer to use a robust governance review process as it offers a more comprehensive protection.
Christos Pap: Aknowledged.
[i-03] Lack of input validation in function parameters
Context: VRCauldron.sol#L114, VRCauldron.sol#L149, VYToken.sol#L66
Description: Some functions of the Variable Rate Yield project lack threshold checks, which could lead to unexpected behaviour in certain situations.
Recommended Mitigation Steps: To address these issues, it is recommended to apply the following mitigations:
setDebtLimits
you could add a require statement thatmin > max
ormin >= max
.setSpotOracle
function could add a require statement thatratio <= 1000000
.setFlashFeeFactor
function a threshold could be added as an upper bound for thefee
value.Yield Team: We rely on our mature governance process to prevent issues for the above.
Christos Pap: Aknowledged.
[i-04] Typographical errors and missing data in comments & NatSpec docs
Context: VRCauldron.sol#L110, VRLadle.sol#L220, VRLadle.sol#L111, VariableInterestRateOracle.sol#L12, VYToken.sol#L20, VYToken.sol#L21, VRLadle.sol#L366
Description: During the audit, several typographical errors and missing data in comments and NatSpec documentation have been identified. Please refer to the
Recommended Mitigation Steps
section for the detailed list.Recommended Mitigation Steps:
address -> address
casting is unnecessary in VRCauldron.sol#L110.implemnting
should beimplementing
.addToken
can also be used to remove a token you could consider renaming theTokenAdded
event toTokenStatusChanged
.NatSpec documentation
.Point
event isn't used in theVYToken
. You could consider removing it.comment
in therepay
function is wrong. Consider replacing it with:The surplus base will be returned to the refundTo address, if refundTo is different than address(0)
.Yield Team: Fixed.
Christos Pap: Verified.
[i-05] Function ordering does not follow the Solidity style guide
Context: VRWitch.sol#L15, VRCauldron.sol#L13, VRLadle.sol#L21, VYToken.sol#L16
Description: The recommended order of functions in Solidity, as outlined in the Solidity style guide, is as follows:
constructor()
,receive()
,fallback()
,external
,public
,internal
andprivate
. However, this ordering isn't enforced through theVariable Rate
codebase.Recommended Mitigation Steps: It is recommended to follow the recommended order of functions in Solidity, as outlined in the Solidity style guide.
Yield Team: We are going to stick to our current style.
Christos Pap: Aknowledged.
Additional Notes
nonReentrant()
modifier. If anyERC777
tokens are supported, a re-entrancy (either a same-function or a cross-function) could be introduced.The protocol team responded:
The text was updated successfully, but these errors were encountered: