Smarts Contracts Security: An overview of vulnerabilities and hacks

Von Yamila Levalle, Security Researcher at Dreamlab Technologies

Blockchain and Web3 vs Web2

A blockchain, as utilised by Bitcoin, is a global distributed ledger that uses cryptographic functions to verify transactions sent over the network. These transactions are verified by nodes (miners) that are rewarded for their efforts with cryptocurrency. Ethereum is also blockchain based, similar to Bitcoin. It is a global, decentralized platform to which anyone can contribute. The development of Ethereum led to the next iteration of the Internet, Web 3.0.

Web3 is a vision for a more decentralized web, where users have more control over their privacy and with decentralized applications that anyone can participate in without monetizing their personal data. The benefits of Web3 are:

  • Everyone on the network has permission to use the service
  • It is designed to work without the control of a central authority, so no one can block or deny access to the service
  • It is designed to work even if nodes fail, there are no single points of failure
  • Ethereum is Turing-complete, which means anything can be programmed
  • The distributed ledger managed by the blockchain is publicly viewable and designed to make it very difficult or impossible to modify or delete transactions

Think of a normal website or application. It has a front end or user interface and a back end that stores and manipulates data. Usually this is hosted on a web server in the cloud or on-premises and is vulnerable to failures, natural disasters, etc. that can cause downtime. With blockchain, there are no such problems. For the application or website to go down, every node running the network would have to be offline.

Web2 apps and hosting solutions are usually controlled by a single entity (Azure, AWS) and that entity can set limits and censor opinions. Due to the immutable nature of blockchain protocols, it is almost impossible to censor or delete data stored in the blockchain. Finally, no one can be stopped from using a service or kicked off the blockchain, because it does not belong to anyone.

However, Web3 is not a panacea. Most decentralized applications are not even truly decentralized. Storing data on the blockchain is expensive, and unencrypted, sensitive data must never be included into the blockchain, because anyone can reverse engineer the bytecode and reconstruct the data. A single line of faulty code could result in millions of Ether being locked up forever or countless millions being stolen in a matter of hours. The resource-intensive nature of mining has also been heavily criticized. Newer protocols have already adopted a Proof of Stake consensus algorithm, which is supposed to be far less resource intensive than Proof of Work. This allows more people to participate in the verification process, because the barrier to entry is lower. More verification nodes mean that the protocol becomes inherently more secure.


What are smart contracts?  

Smart contracts are simply computer programs that run on a blockchain network. The concept was first coined by computer scientist and cryptographer Nick Szabo in the late 1990s. However, they were first implemented by the Ethereum protocol. Smart contracts can be thought of as programs that reside within decentralized blockchains and are executed when all the clauses in the contract are met. A smart contract acts in a similar way to a traditional agreement but negates the necessity for the involvement of a third party, such as an attorney or a notary. Smart contracts are capable of initiating their commands automatically, thus eliminating the involvement of a regulatory body. As a consequence of blockchain’s immutable feature, smart contracts are developed in a manner that is distinct from traditional software. Once deployed to the blockchain, a smart contract cannot be modified or updated for security patches. This encourages developers to implement strong security strategies before deployment, in order to avoid potential exploitation at a later time.

Figure 1: Smart Contracts Characteristics


How are Smart Contracts developed and deployed?

Solidity, the premier programming language built for the Ethereum Virtual Machine (EVM), was intended to facilitate the use of Ethereum as a globally distributed computer, not just a protocol for digital currency. Several new blockchain protocols have since emerged that also use smart contracts written in Solidity. Others have smart contracts written in a variety of languages such as Rust (NEAR, Solana), Python (Algorand) and even Go and C/C++(EOS).

Solidity is an object-oriented, high-level language for implementing smart contracts. It is influenced by C++, Python and JavaScript, and is designed to target the Ethereum Virtual Machine (EVM).  Solidity is statically typed, supports inheritance, libraries and complex user-defined types among other features.


Ethereum Smart Contracts Vulnerabilities

While it is not too difficult to develop software that works as expected, it is much harder to verify that it cannot be used in a way that was not expected. In Solidity, this is even more important because it can define smart contracts to manage tokens, money, or other high valuable items. Also, every execution of a smart contract is public and the source code is frequently available.

Here are some of the most common vulnerabilities that have been researched and reported for Ethereum smart contracts:

  • Re-Entrancy: A smart contract may be vulnerable to a reentrancy attack if it updates state after performing a state-changing operation. When a contract “calls” another account, it can choose the amount of gas it allows the called party to use. If the target account is a contract, it will be executed and can use the provided gas budget. If such a contract is malicious and the gas budget is high enough, it can try to call back in the caller, a reentrant call. If the caller’s implementation did not update his internal state containing balances information, the attacker can use this vulnerability to drain funds out of the vulnerable contract. In the example below https://swcregistry.io/docs/SWC-107#simple-daosol the function withdraw is vulnerable to a reentrancy attack. In line 3, a smart contract’s fallback function may be called, which can call this function again. Since the smart contract has not yet updated its account balances (performed in line 4), the user can end up withdrawing much more than the original amount. The famous breach of the Ethereum DAO smart contract involved exploiting a reentrancy vulnerability. The smart contract included code similar to the example below, allowing a malicious smart contract to drain value from the DAO smart contract:

Figure 2: Solidity function vulnerable to re-entrancy


  • Access Control: Smart contracts often perform authorization, by checking the sender of the message, to restrict the type of action that a user can take. Typically, only the owner of a contract should be allowed to destroy the contract or set a new owner. If the access control code of a smart contract is improperly implemented, a malicious user can gain control of the smart contract. In the example below https://swcregistry.io/docs/SWC-105#multiowned-vulnerablesol the function newOwner is missing the modifier onlyOwner, and could be called by any user to claim ownership of the smart contract:

Figure 3: Solidity Function with access control vulnerabilities


Figure 4: Solidity Function with access control vulnerabilities fixed


  • Integer Overflow / Underflow: An overflow/underflow happens when an arithmetic operation reaches the maximum or minimum size of a type. For instance if a number is stored in the uint8 type, it means that the number is stored in a 8 bits unsigned number ranging from 0 to 2^8-1 (from 0 to 255). An integer overflow vulnerability occurs when a variable is stored in a fixed-size variable without verifying that the value is less than the maximum value that the variable can contain. Integer underflows are a vulnerability commonly caused by subtracting a large number from a small number and storing the result in an unsigned variable. Solidity automatically reverts on integer overflow and underflow, as of version 0.8.0, but it's a common problem in previous versions. The example below https://www.dasp.co/#item-3  is a function that does not check for integer underflow, allowing you to withdraw an infinite amount of tokens (Solidity version < 0.8.0):

Figure 5: Solidity function vulnerable to integer underflow


  • Race Condition / Transaction Order Dependency / Front-Running: In Ethereum, multiple transactions are included in a single block, which means that the state of a contract can be updated multiple times in the same block. Since the Ethereum blockchain is public, all transactions are visible in the mempool for a short while before being executed, and observers of the network can see and react to an action before it is included in a block. Miners are rewarded via gas fees for running code on behalf of externally owned addresses (EOA), so users can specify higher fees to have their transactions mined more quickly. This means that if a given user reveals the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. The simplest example of a race condition is when a smart contract give a reward for submitting information. For example a contract will give out 1 token to the first person who solves a math problem. Alice solves the problem and submits the answer to the network with a standard gas price. Eve runs an Ethereum node and can see the answer to the math problem in the transaction that Alice submitted to the network. So Eve submits the answer to the network with a much higher gas price and as a result it is processed and committed before Alice's transaction. Eve receives one token and Alice gets nothing, even though it was Alice who worked to solve the problem. In the example below https://swcregistry.io/docs/SWC-114#eth_tx_order_dependence_minimalsol the smart contract is vulnerable to race conditions, because a user could observe another user’s transaction to claim the reward and beat them to it by submitting a transaction with a higher transaction fee:

Figure 6: Solidity smart contract vulnerable to race conditions


  • Unchecked Return Value: Some low-level operations in Solidity such as send, which is used to send Ether, do not throw an exception on failure, but rather report the status by returning a boolean. If this return value is unchecked, the caller continues its execution even if the payment failed, which can easily lead to inconsistencies and cause unexpected behaviour in the subsequent program logic. The function below https://www.dasp.co/#item-4 is an example of what can go wrong when the return value of send() is not checked. If the call is used to send ether to a smart contract that does not accept them (e.g. because it does not have a payable fallback function), the EVM will replace its return value with false. Since the return value is not checked, the function's changes to the contract state will not be reverted, and the etherLeft variable will end up tracking an incorrect value:

Figure 7: Solidity function vulnerable to unchecked return value


  • Denial of Service: Denial of service is deadly in the world of Ethereum: while other types of applications can eventually recover, smart contracts can be taken offline forever by just one of these attacks. Many methods can lead to denial of service, including malicious behaviour as the recipient of a transaction, artificially increasing the gas necessary to compute a function, abusing access controls to access private components of smart contracts, taking advantage of negligence,  and so on. In the example below https://www.dasp.co/#item-5 a function of a game contract allows someone to become the president if they publicly bribe the previous one. Unfortunately, if the previous president is a smart contract and causes reversion on payment, the transfer of power will fail and the malicious smart contract will remain president forever:

Figure 8: Solidity function vulnerable to denial of service


For an exhaustive description of Smart Contracts Weaknesses the best source is the SWC Registry. The Smart Contract Weakness Classification Registry  is an implementation of the weakness classification scheme proposed in EIP-1470, aligned to the terminologies and structure used in the Common Weakness Enumeration (CWE) while overlaying a wide range of weakness variants that are specific to smart contracts: https://swcregistry.io/. Also https://www.dasp.co/ is a good resource for the top 10 smart contract vulnerabilities.


Audits, Blockchain and Defi Hacks 2021

According to Chinese cybersecurity firm Slow Mist, since 2012, 602 blockchain hacking incidents have taken place with 238 events coming in 2021 alone. Hacks have grown in sophistication and targeted various areas in the space. The biggest hack to date occurring in 2021 and carried out by an unknown attacker on cross-chain protocol Poly Network. It resulted in the theft of tokens with an equivalent value of $610 million. The incident with Poly Network is one of the many DeFi hacking instances in 2021. Poly Network was fortunate to recover all of the funds. Cream Finance, on the other hand, was not so lucky. The decentralized lending protocol comes in at a distant second, with the two attacks it faced during 2021 taking nearly $150 million that it is still trying hard to recover. Overall, the total amount of money lost due to blockchain hacking in 2021 is nearly $10 billion, which is a $5 billion increase from year 2020.

Cybercriminals are beginning to target unaudited DeFi protocols with increasingly sophisticated attacks. Among the projects that fell victim to attacks in 2021, only about 15 out of the 40 affected DeFi protocols were audited. But it’s worth noting that the affected funds for the audited protocols were significantly less than those that weren't audited. For each audited company, the amount of loss was almost 60% less than those that were unaudited. As a whole, 20.3% of the affected funds in all the protocols hacked this year were from protocols that were audited, while 79.67% were from those that were unaudited:

Figure 9: Audited versus Unaudited Attacked Defi Protocols


The four major reasons DeFi protocols get hacked include coding mistakes, developer errors, misuse of third-party protocols and business logic errors. The most common among these, and possibly the most dangerous, are developer errors and coding mistakes. Inadequately qualified developers rushing to launch a project without a rigorous third-party check can result in protocols that are more susceptible to exploits. This is why there is an ongoing push for an extra measure in improving the security the industry. Security experts recommend a smart contract to undergo an audit, usually through independent auditors. An audit could help detect and possibly rectify vulnerabilities in code and check the reliability of the smart contract's interactions.





References and Related Content:

Smarts Contracts Security: An overview of vulnerabilities and hacks

Alle Blog-Posts