Most Common Vulnerabilities In Solidity: In-Depth Part 2
This article will guide you through some of the most common vulnerabilities in Solidity, including Flashloan, overflow and underflow, tx.origin, Insecure Randomness, and Improper Input Validation Attacks.
If you haven’t already, please check out Part 1 where we explained, Reentrancy, Incorrect Calculations, Oracle Failure/Manipulation, Weak Access Control, and Frontrunning Attacks. You can read it here: Most common vulnerabilities In solidity Part 1
1. Flashloan Attack
In a flashloan attack, an attacker exploits vulnerabilities in the smart contract or the protocol’s design to manipulate the market conditions and make a profit. Here’s a step-by-step breakdown of how a flashloan attack works:
Borrowing the flashloan: The attacker initiates a flashloan from a decentralized lending platform. They borrow a large amount of cryptocurrency without any collateral.
Manipulating the market: With the borrowed funds, the attacker manipulates the market in some way to create favorable conditions for their attack. This can include executing large buy or sell orders to create price movements or exploiting flaws in the pricing mechanisms.
Profiting from the attack: Once the market is manipulated, the attacker executes their main attack, which can vary depending on the specific protocol or smart contract being targeted. The goal is usually to exploit vulnerabilities and make a profit at the expense of other users or the protocol itself.
Here is a methods that developers can employ to reduce the risk:
- Implement limits on the size amount of token that can be borrowed or swaped in a single Transacution, which can help mitigate large-scale attacks.
2. Overflow and underfollow
Overflow and underflow are two common issues that can occur when dealing with numerical operations in solidity. They happen when we exceed the maximum or minimum value that a specific data type can hold. It’s like trying to fit an elephant in a teacup or squeezing a galaxy into a marble! Overflow occurs when the result of an operation is larger than the maximum value that a data type can hold, while underflow happens when the result is smaller than the minimum value.
To prevent overflow and underflow, we can use some smart coding techniques. Here are a couple of methods for prevention:
- Range Checking: Before performing any numerical operation, we can check if the result will exceed the valid range of the data type. If it will, we can take appropriate actions to handle the situation, such as throwing an error or using a different data type. Let’s see an example using a simple addition operation:
2. Using SafeMath Library: Another popular method to prevent overflow and underflow is by using a library like SafeMath. It provides safe mathematical operations for your integers, preventing overflow and underflow. Here’s how you can implement it:
3. tx.origin
authentication vulnerability
The tx.origin
vulnerability occurs when you rely on tx.origin
to authenticate the sender of a transaction. The tx.origin
variable returns the address that originated the transaction. However, this can lead to security risks because it doesn't check the full chain of contract calls.
To explain it in a fun way, imagine you’re at a party, and someone approaches you claiming to be your best friend. But here’s the twist — they actually disguised themselves by wearing your friend’s face!
Similarly, in the blockchain world, malicious contracts can pretend to be someone else to trick your contract into granting access or taking actions on their behalf. This poses a serious security risk.
To prevent such vulnerabilities, instead of using tx.origin
, we can use msg.sender
. Unlike tx.origin
, msg.sender
always returns the immediate sender address, which ensures that the identity is not spoofed by intermediary contracts. It's like checking the person right in front of you and not relying on someone else's word.
Here’s an example to illustrate the difference and how to use msg.sender
:
In the above example, we’re using tx.origin
to check if the caller is the contract owner. This can be exploited by malicious contracts that pretend to be the owner using intermediary contract calls.
Let’s fix this vulnerability using msg.sender
:
In the fixed contract, we have replaced tx.origin
with msg.sender
to ensure that the immediate sender is authenticated. By doing this, we prevent the vulnerability and make our contract more secure.
4. Insecure Randomness
A Insecure randomness attack, also known as a random number manipulation attack, occurs when an attacker can predict or manipulate the outcome of a random number generation process. In the smart contracts, this can be a serious issue because random numbers are often used for important operations like determining winners in a lottery or selecting options in a game.
Now, the first step in preventing randomness attacks is to understand that randomness is hard to achieve in a deterministic environment like the blockchain. However, there are a few techniques we can use to enhance randomness and make it more secure. One popular method is to use an oracle for randomness, which fetches random numbers from external sources.
Here’s an example of how you can implement a basic prevention method using an oracle :
In this example, we’re using the Chainlink VRF (Verifiable Random Function) to generate random numbers. The getRandomNumber
function requests randomness by calling requestRandomness
and passing the keyHash
and fee
. The fulfillRandomness
function is called when the randomness is generated. You can use the randomResult
in your contract logic.
5. Improper Input Validation
Improper Input Validation attacks can be a real headache if not handled carefully. These attacks occur when a smart contract fails to properly validate the input received from users, allowing malicious actors to exploit vulnerabilities in the code.
To prevent improper input validation attacks, you can follow these steps and use code snippets as examples:
Validate User Input: Ensure that the input received from users meets the expected criteria. This can include validating the format, length, and type of the input. Here’s an example for validating a user’s age:
Use Safe Math: When performing arithmetic operations, use the SafeMath library to prevent overflow and underflow errors. Here’s an example:
Implement Access Controls: Limit the access to certain functions or data to trusted parties only. This prevents unauthorized users from manipulating the contract’s state. Here’s an example using the OpenZeppelin library’s Ownable
contract:
Use Modifiers: Modifiers can be used to add reusable pre or post-conditions to functions. They allow you to enforce input validation checks consistently across multiple functions. Here’s an example:
Remember, these examples are just a starting point, and you can adapt them to fit your specific needs. Always thoroughly test your smart contracts to ensure their security.
🎉🎉 Congratulations! Now, you can prevent Flashloan, overflow and underflow, tx.origin, Insecure Randomness, and Improper Input Validation Attacks in your contracts.
About BuildBear:
BuildBear is a platform for testing dApps at scale, for teams. It provides users with their own private Testnet to test their smart contracts and dApps, which can be forked from any EVM chain. It also provides a Faucet, Explorer, and RPC for testing purposes.
BuildBear aims to build an ecosystem of tools for testing dApps at scale for the teams.
Subscribe to my newsletter
Read articles from BuildBear directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
BuildBear
BuildBear
BuildBear is a platform for testing dApps at scale, for teams. It provides users with their own private Testnet to test their smart contracts and dApps, which can be forked from any EVM chain. It also provides a Faucet, Explorer, and RPC for testing purposes.