CosmWasm security spotlight #4

JCsec
Oak Security
Published in
4 min readMar 11, 2024

Are you a CosmWasm Smart Contract developer? A random Cosmonaut peeking into this cool tech? A Solidity auditor looking for new knowledge? Then keep reading!

There is a lot of great content about security findings and auditing of Solidity Smart Contracts. Sadly, that is not the case for CosmWasm… yet!

Rounding issues

Mathematical operations are the bread and butter of almost any given smart contract out there. It will not surprise you to know that they are not free of security concerns; for example, integer overflows and underflows are well-known by most developers.

The most commonly found math-based security issues nowadays are not over-/underflows. Instead, rounding and truncation are the culprits. They occur depending on the data type in most programming languages. Such rounding errors and truncation are common in smart contracts, and we regularly see issues during our audits when assets with different numbers of decimals are handled.

Typically, rounding issues start with a division but can have very different outcomes depending on each scenario. Some are inevitable and negligible, while others can obliterate a protocol if exploited for profit.

pub fn calculate_fee(in_amount: Uint128) -> StdResult<Uint128> {
Ok(in_amount * (FEE_PERCENT/100))
}

Rounding issues appear when the result of a division is less precise than the design requires. This can take the form of sending or receiving one token unit less or causing a ratio to lose a significant amount of precision. For example, when doing integer division 19/10 will be truncated to 1, significantly affecting the result of any subsequent operation.

Some of the most common sources of error are:

  • Ratio calculations using integers.
  • Rounding against the protocol. That is, the contract loses a tiny amount per operation.
  • Operating assets with different numbers of decimals without prior normalization.

Let’s take a look at some examples from out audit reports:

[CRITICAL] Finding #3 “Multiple rounding issues may cause zero rewards to be distributed.”

This is a classic example of ratios expected to be between 0 and 1 but held in integer data types. In this case, the ratios are used as part of the rewards calculation mechanism, resulting in a distribution of zero tokens to the users.

[MAJOR] Finding #4 “Possible inconsistencies when configuring decimal values.”

Multiple contracts work together in this protocol, taking information about assets stored in different contracts. The number of decimals of each asset is not checked before operating with both of them, which causes incorrect calculations or even zero swaps.

In addition, a maximum ratio was hardcoded for assets with 6 decimals but applied to every asset. It yielded incorrect results in calculations with different decimals or even truncated the results to zero.

[CRITICAL] Finding #1: “Attackers can cause a consensus failure by sending coins through IBC.”

This case is different as it is not a CosmWasm smart contract but a Cosmos SDK module.

A chain halt could be triggered when a zero-amount coin is passed to the affected function. As the module uses a hardcoded scale factor, attackers could trigger this condition by sending an amount smaller than the scale factor but valid. When this amount gets divided by the scale factor, it results in zero.

Hunt the bug!

Go practice in the sixth challenge of Oak Security’s CosmWasm Security Dojo, and hunt this bug in a small lending contract. Peeking into the exploit too soon counts as cheating! :P

How to avoid this issue?

Remediation is not as straightforward as you may suspect, given the wildly different scenarios where this issue may surface. However, following this list of tips, you can avoid most rounding and truncation issues.

  • Multiplication should be performed before division to avoid indirectly reducing precision. However, be aware of potential overflows when multiplying.
  • If needed, make use of scaling factors to increase the resulting precision. Again, be aware of potential overflows. In the latest step, downscale the result back to normal.
  • In cases where rounding errors will inevitably affect the result, always round in favor of the protocol instead of the user. For example, an attacker cannot extract additional value this way during pricing or token amount calculations.
  • When calculating ratios, use cosmwasm_std::Decimal or similar libraries. Doing so will grant your operations 18 decimals of precision while providing convenient methods to convert and operate with other data types.
  • When operating with multiple assets, ensure the number of decimal places matches. If not, normalize them before operating so the decimals are in the same position.

You should pay attention to all of the above, not just one. For example, even if you use Decimal values to calculate fees, those can yield a truncated zero result in some scenarios. In those cases, you should follow the “round in favor of the protocol” principle and charge a fee of 1 token instead of zero.

Contact me!

If you have any questions or comments or want to know more about Oak Security and Solidified, please drop a line to @jcr_auditor on Telegram or email me at jcr@oaksecurity.io.

Check out my GitHub for further educational content on Smart Contract security and auditing, such as the CosmWasm security and audit roadmap!

Telegram | Email | Twitter | Github | LinkedIn

Disclaimer! Although most of the reports I link are of audits I participated in, I also include others. I do not claim ownership of any kind of the external resources included in these articles :)

--

--

JCsec
Oak Security

Smart Contract security auditor specialized in CosmWasm. Follow me on Twitter @jcsec_audits and Github https://github.com/jcsec-security