This article will walk you through some of the most common vulnerabilities in Solidity, such as Reentrancy, Incorrect Calculations, Oracle Failure/Manipulation, Weak Access Control, and Frontrunning Attacks. Not only that, but we’ll guide you on the solutions and prevention techniques to keep your contracts safe.
Reentrancy Attack
So, what’s a reentrancy attack? Picture this situation: You own a candy shop, and you’re handing out candy to the kids in the neighborhood. A kid comes to you asking for a candy and as soon as you open the jar to give it to them, they ask for another. While you’re busy getting the next candy, they steal from the open jar. Not cool, right?!
A similar thing happens in a reentrancy attack. A malicious contract tricks a contract into executing code it shouldn’t before the first function call can fully complete. This can cause the victim’s contract to give out way more funds than the coder originally intended.
Our “Victim” contract here allows folks to deposit and withdraw funds. But an attacker could call withdraw()
repeatedly before the balance[msg.sender] = 0;
line ever gets executed, stealing way more Ether than they originally had.
To defend against this attack, we introduce the Checks-Effects-Interactions (CEI) pattern. Just like the order of the words suggests, first we CHECK conditions, then we EFFECT changes, and finally, we INTERACT with external contracts. Let’s understand this!
First, we check the balance, then modify the balance (Effects), then call the external function (msg.sender.send(amount)) which can be a potential source of reentrancy attacks (Interactions).
Incorrect Calculation
Smart contracts work with integer values, without decimals, and they round down automatically.
Let me give you an example of Solidity.
Here the calculate
function divides a
by b
, but if b
is larger than a
it will round down to zero. It will also round down when the division of a
and b
results in a decimal number.
To avoid such errors, we’re gonna use SafeMath library.
As you know if you’re writing in Solidity 0.8.x, all arithmetic operations like add, subtract, multiply, and divide are already safe. No more guard needed!
Even though Solidity 0.8.x has safety measures, the integer division is still a tricky part. If you divide 5 by 2, you may expect 2.5, but in Solidity you’ll get 2 (it dismisses the decimal and rounds down). So if you’re working with fractions, you want to handle them properly.
An approach many developers use (and which might save you lots of headaches) is multiplying before dividing:
In this version, the multiplication by precision is done before the division, ensuring you keep the precious accuracy.
Oracle failure/manipulation
Oracles are essential external entities that feed smart contracts with real-world data. But they come with their own issues, and the most common of them all is Oracle failure/manipulation attack. To grasp this better, let’s walk through it step-by-step.
Oracle Failure: This is when Oracle is unintentionally providing incorrect data, maybe due to a bug or an external issue.
Oracle Manipulation: It refers to when the Oracle is purposefully manipulated to provide false data, often causing mayhem in the Defi ecosystem.
The key to tackling Oracle attacks revolves around decentralizing the source of data. Let’s break down the best practices:
Multiple Oracles: Instead of using just one Oracle, use multiple Oracles to source data. If one gets manipulated or fails, others can still provide the right data.
Time Locks: Add a time gap between when data is received and when it’s implemented. Given enough time, if someone spots a manipulated data point, they can prick the alarm bells!
Weak Access Control attack
Weak Access Control, in the context of smart contracts, occurs when restrictions on who can call certain functions in your contract and under what conditions they can do so are ineffectively implemented or downright absent. It’s like leaving the doors of your house wide open and expecting that no one will enter without your permission.
A classic example is a function that allows only the owner to withdraw funds but lacks a proper check for who the caller of the function is.
Implement Access Control Lists (or ACLs): Access Control Lists are essentially a list of permissions attached to an object. They specify what users can do and what they can’t. So, for instance, for a function that withdraws funds from a contract, only the account owners would get the ticket to the show.
Use Modifier Functions: In Solidity, we have this super useful feature called ‘Modifiers’. These are conditions that you can use to restrict access to your functions. For instance, you could create an
onlyOwner
modifier that throws an exception if anyone other than the owner tries to meddle with your contract.
In this example, the contract is initiated with the creator of the contract as the owner. The onlyOwner
modifier is created to restrict access to sensitive functions, like mySensitiveFunction
. If anyone who is not the owner tries to call the function, the modifier function will throw an exception, keeping our contract safe.
Frontrunning Attack
Imagine if a player sees what cards you’re about to play in a game of poker and then rearranges his deck to win. That’s what a frontrunner does in the blockchain. Frontrunners observe pending transactions on the blockchain and then place their identical transactions with a higher gas price, making the miners more likely to perform their transactions first, allowing them to profit at others’ expense.
Gas Price Limitations: Introduce mechanisms that limit the maximum acceptable gas price for transactions. This can help prevent front-runners from drastically increasing the gas fees to prioritize their transactions.
Off-Chain Oracles and Order Matching: Leverage off-chain oracles and order matching mechanisms to execute sensitive operations off-chain, reducing the exposure to front-running attacks.
🎉🎉 Congratulations! Now, you can prevent Reentrancy, Incorrect Calculations, Oracle Failure/Manipulation, Weak Access Control, and Frontrunning Attacks in your contracts.
Watch out for “Most Common Vulnerabilities In Solidity: In Depth Part 2”
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.