The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

If accepted token price crash, attack can abusing it to mint EUROs and get profit

Summary

No checking for max/min price of collateral when calculating price of collateral for minting EUROs lead to scenario that user make profit when collateral price crash.

Vulnerability Details

Chainlink aggregators have a built-in circuit breaker to prevent the price of an asset from deviating outside a predefined price range. This circuit breaker may cause the oracle to persistently return the minPrice instead of the actual asset price in the event of a significant price drop. Price of collateral is calculated as below:

function tokenToEurAvg(ITokenManager.Token memory _token, uint256 _tokenValue) external view returns (uint256) {
    Chainlink.AggregatorV3Interface tokenUsdClFeed = Chainlink.AggregatorV3Interface(_token.clAddr);
    uint256 scaledCollateral = _tokenValue * 10 ** getTokenScaleDiff(_token.symbol, _token.addr);
    uint256 collateralUsd = scaledCollateral * avgPrice(4, tokenUsdClFeed);
    (, int256 eurUsdPrice,,,) = clEurUsd.latestRoundData();
    return collateralUsd / uint256(eurUsdPrice);
}

As can be seen, price of collateral is calculated based on average price in 4 hours of token in chainlink by using function avgPrice(). It is used in function euroCollateral() to calculate max mintable EUROs token and check for liquidation in the vault:

function euroCollateral() private view returns (uint256 euros) {
    ITokenManager.Token[] memory acceptedTokens = getTokenManager().getAcceptedTokens();
    for (uint256 i = 0; i < acceptedTokens.length; i++) {
        ITokenManager.Token memory token = acceptedTokens[i];
        euros += calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr));   // <-- used to calculate total value of token
    }
}

function maxMintable() private view returns (uint256) {
    return euroCollateral() * ISmartVaultManagerV3(manager).HUNDRED_PC() / ISmartVaultManagerV3(manager).collateralRate(); // <--- used to check max mintable EUROs token
}

When token price crash, user can get profit by using following scenario:

1, Price of token massively drop under min range for 4 hours, currently price returned from tokenToEurAvg() function is equal to min range due to mechanism of chainlink
2, Attacker buy collateral token after price drop
3, Deposit token to vault
4, Minting EUROs token, get profit from them because collateral token is overpriced, leaving vault under collateralized.

In the past, it is already happened when luna collapse. In the token list, WBTC can be because it is a bridged asset and if the bridge is compromised/fails then WBTC will depeg and will no longer be equivalent to BTC, lead to massive drop

Impact

Attacker can get profit when price drop under min value.

Tools Used

Manual review

Recommendations

When checking max mintable, there should be minPrice and maxPrice for each token, if price of token is not in that range, skip them:

function euroCollateral() private view returns (uint256 euros) {
    ITokenManager.Token[] memory acceptedTokens = getTokenManager().getAcceptedTokens();
    for (uint256 i = 0; i < acceptedTokens.length; i++) {
        ITokenManager.Token memory token = acceptedTokens[i];
+       if((token.minPrice * getAssetBalance(token.symbol, token.addr) > calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr))
        || (token.maxPrice * getAssetBalance(token.symbol, token.addr) < calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr)))
            continue;
        euros += calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr));
    }
}

For better soution, user other off-chain oracle providers, or using Uniswap's TWAP when the price is not in the range min/max price.

Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

chainlink-minanswer

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

chainlink-minanswer

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!