What a smart contract audit is, and how to conduct one Smart contract benefits and best practices for security
Tip

12 smart contract vulnerabilities and how to mitigate them

Smart contracts execute tasks automatically when specific events occur, and they often handle large data and resource flows. This makes them particularly attractive to attackers.

As smart contracts are increasingly used to secure digital assets, developers face an array of security threats. Recent high-profile attacks -- including Penpie's $27 million loss and Cetus' $223 million hack -- underscore the importance of proper coding to prevent vulnerabilities.

Smart contracts execute processes, transactions and other tasks when specific events, conditions and logic are met, depending on how they are programmed. They are deployed on a blockchain, such as Ethereum or other distributed ledger infrastructure, where they listen for events and updates from cryptographically secure data feeds called oracles.

Many industries, including finance, healthcare and insurance, use smart contracts to control the flow of large amounts of valuable data and resources, such as transferring money, delivering services and unlocking protected content. This naturally makes them an attractive target to malicious actors.

Security must be a top priority when designing and developing a smart contract. Once a smart contract is deployed to a blockchain, it is difficult or impossible to patch; it must be removed, recreated and redeployed. Plus, vulnerabilities in a smart contract will be accessible to anyone once the smart contract is on a blockchain.

When deploying a smart contract written in Solidity on the popular smart contract platform Ethereum, development teams need to be especially aware of the following attack vectors and how to eliminate them.

1. Reentrancy attacks

Reentrancy attack vectors exist because Solidity smart contracts execute imperatively: Each line of code must execute before the next one starts. This means that when a contract makes an external call to a different contract, the calling contract's execution pauses until the call returns. This effectively gives the called contract temporary control over what happens next, creating the possibility of an infinite loop.

For example, a malicious contract could make a recursive call back to the original contract to withdraw resources without waiting for the first call to complete, so the original contract can never update its balance before the function completes. Forms of reentrancy attacks include single-function, cross-function, cross-contract, cross-chain and read-only. GitHub maintains a list of exploits.

Fix: This vulnerability occurs when the code logic of a smart contract is flawed. Developers need to carefully design external calls and always check and update the contract's state, such as decreasing the ether balance before fulfilling requests to send funds. Adding a reentrancy guard can prevent more than one function from executing at a time by locking the contract. Various audit tools, such as Slither and Securify, can check for the presence of the different types of reentrancy vulnerabilities.

Example: In a 2024 reentrancy attack on the Penpie decentralized finance (DeFi) protocol, attackers stole $27 million worth of ether, Ethereum's native cryptocurrency.

2. Oracle manipulation and flash loan attacks

Smart contracts access and consume external data from outside the blockchain using an oracle. This lets them interact with off-chain systems, such as stock markets. Incorrect or manipulated oracle data can erroneously trigger the execution of smart contracts; this is known as the oracle issue.

Many DeFi applications have been exploited using this method, the favorite being a flash loan attack. Flash loans are essentially unsecured loans with no limit as to how much can be borrowed so long as the loan is repaid in the same transaction. Attacks use these loans to distort asset prices to generate profits while still abiding by a blockchain's rules.

Fix: Using a decentralized oracle, such as Chainlink or Tellor -- or even multiple oracles -- is the easiest way to ensure a contract receives accurate data. Such oracles make it harder and more expensive for an attacker to interfere with the data.

Example: The Abracadabra decentralized crypto-asset lending platform experienced a flash loan exploit in which attackers stole around $13 million in ether.

3. Insecure randomness

Cryptographic algorithms rely on sources of random numbers when generating keys and performing other actions for smart contracts. A fundamental principle of cryptography is that random numbers must be unpredictable, and while that sounds obvious, it's often quite challenging to achieve. If the sources of randomness are not strong and there is any predictability in the values that they generate, this could provide several opportunities for attacks to circumvent the cryptographic protections that are fundamental to the integrity of smart contracts.

Fix: Only use cryptography based on accepted standards for random number generation. NIST has an entire research project and a suite of standards focused on random number generation.

Example: The $FFIST cryptocurrency token suffered an attack that resulted in a loss of around $110,000. The attack was traced back to a predictable source of randomness.

4. Business logic errors

A business logic error is a general term for a design error within a smart contract or between smart contracts. The design error causes the contract to behave differently than it was intended to behave. Attacks can take advantage of business logic errors to manipulate contracts and steal funds.

Fix: Developers should thoroughly test all contract code, including all combinations of business logic, and verify that the observed behavior exactly matches the intended behavior in each case. Consider using manual and/or automated processes and tools to analyze contract code for possible business logic errors.

Example: The SIR.trading DeFi protocol experienced a logic flaw attack in March 2025 that resulted in the theft of around $355,000.

5. Force-feeding attacks

Force-feeding attacks take advantage of the fact that developers cannot prevent a smart contract from receiving ether. This makes it easy to transfer ether to any contract -- force-feeding it -- to change the balance of ether it holds and thereby manipulate any function logic that solely relies on the expected balance for internal accounting, such as paying out a reward if a balance increases above a certain level.

Fix: It is impossible to stop contract balance manipulation in this way. Never use a contract's balance as a check or guard within a function because the actual ether balance might be higher than the balance expected by the contract's internal code.

Graphic listing the 12 top smart contract vulnerabilities.

6. Lack of input validation

All software needs to validate inputs; this has been a core principle of software development for decades. It is dangerous for software developers to assume that all inputs to software will be as expected. Attackers can craft inputs that cause crashes, potentially temporarily disrupting access to smart contracts, or that cause software to act in unexpected ways. More concerning is the use of inputs to alter data or change the software itself, both of which can be used to manipulate smart contracts.

Fix: Developers should ensure all input is carefully validated as being exactly as expected before use. Add double-checks to the contract just in case an unexpected input somehow manages to pass validation and be processed. For more information, see the Solidity documentation on error handling.

Example: The Onyx DeFi protocol faced a $3.8 million loss following an attack on an input validation vulnerability.

7. Denial of service

Like any online service, smart contracts are vulnerable to DoS attacks. By overloading services, such as authentication, an attacker can block other contracts from executing or generate unexpected contract reverts, for example, where unused gas is returned and all state is reverted to the state before the transaction began to execute. This can result in auction results or values used in financial transactions being manipulated to the attacker's advantage.

Fix: Making these attacks costly for attackers is the best way to deter them. Time-lock puzzles and gas fees are just some of the ways of increasing an attacker's costs. Ensuring calls are only made to trusted contracts also reduces the likelihood of a DoS attack causing serious problems.

Example: This is not an example of an attack, but in April 2025, the Ethereum Improvement Proposal 7907 upgrade was approved to help prevent contracts from falling victim to DoS attacks through gas metering.

8. Integer underflows and overflows

Integer underflows and overflows occur when the result of an arithmetic operation falls outside the fixed-size range of values: zero to 255 in the case of integer type uint8. Values higher than 255 overflow and are reset to zero, while values lower than zero reset to 255. This causes unexpected changes to a contract's state variables and logic, triggering invalid operations.

Fix: Since version 0.8.0 was released at the end of 2020, the Solidity compiler no longer allows code that could result in integer underflows and overflows. Check any contracts compiled with earlier versions for functions involving arithmetic operations or use a library, such as SafeMath, to check for underflow and overflow issues.

Example: The Cetus decentralized exchange hack in May 2025, which cost an estimated $223 million in losses, was the result of a missed code overflow check.

9. Access control vulnerabilities

Blockchains are accessible to anyone. Never save confidential or sensitive information to a blockchain unless it is encrypted. State variables and functions within a smart contract can also be visible and accessible to other smart contracts, which leaves them open to possible misuse or abuse.

Fix: Developers should always implement proper access controls following the principle of least privilege by using Solidity's state variable and function visibility specifiers to assign the minimum level of visibility as is necessary and no more.

Example: The KiloEx decentralized exchange suffered an approximate $7 million loss due to a lack of access controls in a smart contract.

10. Gas griefing

To perform a transaction or execute a smart contract on the Ethereum blockchain platform, users must pay a gas fee. It is paid to incentivize validators (miners) to commit the resources needed to verify transactions. The price of gas is determined by supply, demand and network capacity at the time of the transaction.

Gas griefing occurs when a user sends the amount of gas required to execute the target smart contract but not enough to execute subcalls -- calls it makes to other contracts. If the contract does not check if the required gas to execute a subcall is available, the subcall will not execute as expected. This can have a significant effect on the application's logic.

Fix: No effective technique to prevent gas griefing exists. Developers should code contracts so they set the amount of gas to be sent, not the user. A rise in gas costs, however, could mean that the transaction fails.

11. Transaction order dependence attacks (frontrunning)

Smart contracts are publicly visible from the moment they are submitted to the network as a pending transaction. This enables a miner of a block to select the transaction with the highest gas fees. For example, users can include a priority fee -- a tip -- to incentivize miners to prioritize their transaction ahead of other transactions in the same block. However, this also enables attackers to watch for opportunities where they can front-run profitable contracts by submitting an identical contract, but with a higher gas fee, so their contract is processed first. Because these attacks have to be implemented in fractions of a second, they are usually performed by bots or miners themselves.

Fix: These attacks are tricky to avoid. One option is to only accept transactions with a gas price below a predetermined threshold. Or, use a commit-and-reveal scheme that involves a user first submitting a solution hash instead of the cleartext solution so it can't be viewed by potential frontrunners until it is too late. Various smart contract audit tools can detect if code introduces frontrunning vulnerabilities.

12. Timestamp dependence

The node that executes the smart contract generates timestamp values. Due to the distributed nature of the Ethereum platform, it is almost impossible to guarantee that the time on every node is correctly synchronized. A node can then manipulate the timestamp value it uses to craft a logic attack against any contract that relies on the block.timestamp variable to execute time-critical operations.

Fix: To avoid this vulnerability, developers should not use the block.timestamp function as a control or logic check, or as a source of randomness.

Keeping smart contracts vulnerability-free

For smart contracts to be smart and secure, development teams must build in security from the start and rigorously test their logic and code execution.

Contract code is difficult to patch after it is deployed. Getting security right the first time is imperative. Always follow smart contract security best practices. Unless the development team includes dedicated smart contract security specialists who can audit smart contract code for logic flaws and other vulnerabilities by unit testing each function, use an auditing service specializing in smart contracts to identify any security issues.

Karen Scarfone is a general cybersecurity expert who helps organizations communicate their technical information through written content. She co-authored the Cybersecurity Framework (CSF) 2.0 and was formerly a senior computer scientist for NIST.

Dig Deeper on Threats and vulnerabilities