Types of most frequent smart contract vulnerabilities
It would be marvelous if there were codes without vulnerabilities. This, however, is hardly possible. Any piece of code has its issues, which need to be detected and patched, which is what smart contracts auditing is for. Smart contracts can contain vulnerabilities, and attackers would make use of them, so the consequences of possible vulnerabilities and bugs must be avoided. But what is the enemy that experts have to face?
Most common types of vulnerabilities
The list of possible vulnerabilities is very long. Moreover, new ones are discovered every now and again. Some are encountered by experts more often than others::
- Reentrancy. One of the most known and frequently encountered (if not the most) among the vulnerabilities exploited by hackers. In this case one smart contract calls another another, but the addressed contract can also make a back (reentrant) call, when the initial caller has not yet updated (or fails to update) its state. It leads to a possibility of the so-called ‘reentrancy attack’, when attackers use the callback function and create a contract with an external address, using malicious code. As a result they continuously call the withdrawal function before the initial smart contracts could update its state, which can empty the wallets of victims (the malicious contract calls the deposit function, while the vulnerable contract records the transfer and sends the deposited sum to the malicious address and repeats the action as much as necessary, because the update has not passed). A lot of great ‘robberies’ were made due to this vulnerability (including Uniswap, Cream Finance, Siren protocol and much more).
- Front running. It is a ‘dangerous side’ of being public (when the transactions are visible to the entire network to allow miners to choose preferable ones). This vulnerability allows the attacker to see the probable outcome before the transaction confirmation on the blockchain, so that they can copy the victim’s contract, submit it with a higher fee (front-run the owner) and steal the owners’ opportunity to submit it first. It is very hard to detect and avoid the problem, but still there are ways to make the transaction secure (such as the gas limiting or pre-commit scheme, which allows to submit a hash instead of the actual data at the first commit).
- Integer overflow/underflow. A frequent and common vulnerability to many code languages, one of them being Solidity. It depends on the size of the smart contract (which equals 4.3 billion Ether). If the value is reduced to zero, it will return to the maximum. Attackers use a malicious address to make a zero balance and force a real smart contract to cycle back to the maximum possible value. The attacked smart contract presumes that the address has a true value of 4.3 billion and allows ‘infinite’ withdrawals until the wallet is empty. This type of vulnerability undermines the smart contract inner logic which leads to huge losses. Updating the Solidity compiler version to the one which automatically checks over- and underflows is a good measure to avoid it.
- Incorrect use of functions, such as creating random numbers within the chain without restriction on the right to call on behalf of another contract and a number of other checks, makes the random number pre-checkable. And the use of private mappings as a secure storage can lead to data being compromised, and if they are used in a sensitive part of the project, lead to sad consequences.
- Logic errors. Logic errors (such as typographical errors, specification misinterpretations, etc.) are very common blockchain smart contract vulnerabilities, which reduce the security level dramatically. All of them can be detected and corrected during the smart contract auditing phase, which should be ignored under no circumstances.
- Block gas limit. This limit stops of the blocks from growing too much (that is, if a transaction requires too much gas, it will not pass, because it will exceed the block’s threshold). But if the data stored in arrays can be accessed through loops, the transaction runs out of gas. It may happen when the number of elements in an array grows. The vulnerability is even more dangerous than the previous ones, because it can be overlooked on the testing stage (the test data is usually smaller and the contracts pass the tests). Then the users get into trouble when the amount of data increases. It may lead to bonuses non-cancellation when the loops are used for payout pushing or even to a Denial of Service attack.
- Default visibility vulnerability. It happens when the visibility of functions (which defines if the function is called internally or externally) is not specified and functions which should be private or called within the smart contract are stated as ‘public’ by default, thus the data and functions which must not be seen by anyone else are open for ‘malicious use’.
- Timestamp dependence. This vulnerability refers to a specific function (block.timestamp) which displays the StartTime and the EndTime. A smart contract uses it to get actual time and its value is given by the node. So a dishonest miner can manipulate the time and change the output. To avoid this problem, it is advised not to use the function for receiving current time and not use it in critical smart contract components. If the user can not avoid using the function at all (which also happens), it is advised to allow it a small range of error, so if the value returned by the node falls within this range, the impact on the contract will not be dramatic.
- Lack of parameters or precondition controls. This quite common vulnerability concerns the absence of function parameter verification or necessary check-ups, the validation of operations or the absence of access control (so that any user can call any function without verification). But, in most cases, writing instructions for the functions (with parameters, preconditions and performing operations) and sticking to secure design patterns may help to avoid the falling into the vulnerability.
- Token amount calculation error. It appears when smart contracts dealing with huge amounts of money in tokens or ETH value come into question. It may mean incorrect percentage, fees or profit calculations. They include incorrect decimal handling, incorrect order operations when fees are calculated (it leads to accuracy loss) or an accuracy constant missing (or forgotten in mathematical operations). The result might be fund losses or locking of tokens for indefinite duration (even for ever). It can be avoided by good auditing, which checks the mathematical operations’ correctness.
- Exceptions issue. It happens when specific exceptions are handled improperly. As long as exception handling is based on the interaction among the contracts, vulnerable contracts can be under attack and the transactions might be rolled back.
- ERC20 issue. It happens when custom implementations of the standard of the token (which is ERC20) take place. It brings about differences between a new token and the standard, which can be quite dangerous. Being rather small and usually not noticeable during simple testing, it may lead to a missing return value in the transfer function or to non-functional methods of smart contracts (and to stuck funds and contract blocking later).
Conclusion
This list can be longer, as there are a lot of issues, some of which are rarer, the others are more common and frequent, and many of them are not noticed from the first glance. Some bugs are easy to find, some of them, such as incorrect use of functions and logical errors are vulnerabilities that cannot be uncovered without a deep understanding of the product and are detected by manual testing. Taking care of the data and contracts, regular audits and updates will help to avoid the danger in the future and ‘fly safe’ in the blockchain world.