15,000 USDC
View results
Submission Details
Severity: high
Valid

High - More than 18 decimals make users impossible to liquidate and mint huge amounts of DSC

Summary

The protocol handles in unexpected ways collateral tokens with other than 18 decimals. There are two cases: when they have less than 18 decimals and when they are more than 18 decimals. Since both cases have different outcomes, we created two different issues. In this one, we will showcase the case where the collateral token has less than 18 decimals.

This, basically, will allow minting way more DSC tokens than we should plus, as a bonus, we can obtain a crazy good health factor that will allow us to be almost impossible to liquidate.

Vulnerability Details

The protocol is set to be always overcollaterized at least at 200%. That means when you deposit some collateral amount, the maximum amount you are able to mint of DSC will be 50% of the USD value of the collateral.

Let's see a few examples.

First, we are going to use WETH as collateral. WETH has 18 decimals and in our sample, its value is 2000 USD / WETH. So if we add 1 ether of WETH (1e18 WETH) as collateral, the maximum amount of DSC we must be able to mint is 1000 ether of DSC which is equal to 1000e18 DSC (DSC is valued at 1 USD / DSC and its token has 18 decimals), so you will get basically 1000 USD in DSC value.

That is fine. But what happens if we have a collateral token with, for example, 24 decimals? Let's call this token MOCK2 and its value will be 1 USD / MOCK2.

If we add 200 MOCK2 tokens as collateral (so 200e24, since 1 "full" MOCK2 token has 24 decimals), the maximum amount of DSC we should be able to mint is 100 ether of DSC = 1e18 DSC = 100 USD. But... the real maximum amount of the DSC token we can mint is much more different. How much?

100e24 DSC. In other words, 100_000_000 ether of DSC so... 100_000_000 USD!

But, contrary to what happened in the other finding we provided where the protocol breaks when the collateral token has less than 18 decimals, here, instead of reverting when minting the maximum amount, something else happens. Something really interesting.

Because let's be honest. If an attacker tries to mint a crazy huge amount of DSC, they will have to go to a DEX to sell them and they might not be able to sell a huge amount (like 1 billion of DSC) without being affected by the slippage.

But they could exploit this second option, also really interesting: Instead of minting the maximum amount of DSC allowed by their collateral they could mint a smaller amount and enjoy the benefits of being almost impossible to liquidate and at the same time, obtain a good profit. Let's see an example.

Using the example I showed previously, when adding 200 MOCK2 tokens, if instead of minting the maximum amount of DSC, you mint a smaller amount, for example, 9e22, you still can mint a huge amount of DSC from your small collateral input but at the same time you will gain a huge health factor.

In fact, with the example I gave, by adding 200 MOCK2 tokens as collateral (valued at 200 USD since 1 USD / MOCk2) and minting a "conservative" amount of DSC of 9e22, you will get:

  • 90_000 ether of DSC, valued at 90_000 USD

  • A health factor of 1111e18 (which is much bigger than the liquidation threshold, which is 1e18) making your account almost impossible to liquidate)

By doing this second approach, you could also add other collateral tokens with normative decimals (18) like WETH as collateral, and mint the maximum amount all the time and it would affect almost nothing your health factor. This would allow you also to be constantly liquidating other users (when they are under the liquidation threshold) and swapping some of your "free" DSC for their collateral, allowing you to increase even more your gains from this.

To showcase this issue, we have created a plug-and-play POC you can test. To try it, create a file in your test folder called POC_Extremly_Healthy_Breaking_Minting.t.sol and paste the content of this gist: https://gist.github.com/TheNaubit/bc71e5228eaa55eb8c2f7677352621cd

Then run the POC by running this command: forge test --match-contract POC_Extremly_Healthy_Breaking_Minting -vvv

Impact

This breaks the protocol functionality since allows to mint too much DSC, be impossible to liquidate and in general, exploit the protocol and all its functionalities.

Tools Used

Manual review and Foundry.

Recommendations

Review the entire approach for the collateral math when the collateral token has more than 18 decimals. One of the key places to check is https://github.com/Cyfrin/2023-07-foundry-defi-stablecoin/blob/d1c5501aa79320ca0aeaa73f47f0dbc88c7b77e2/src/DSCEngine.sol#L366C38-L366C38, since almost all the functions depend on this and this function is assuming every collateral token has an 18 decimals precision.

Support

FAQs

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