Smart Contract Security Fundamentals
Tomohiro Iida · Published April 7, 2026
A smart contract is difficult to fix once deployed, and a vulnerability translates immediately into the loss of assets. This article covers four common vulnerability patterns, five principles of secure design, and the toolchain used in practice.
Key takeaways
- Smart contract vulnerabilities are well enough understood to be catalogued as the SWC (Smart Contract Weakness Classification); reentrancy, integer overflow/underflow, access-control gaps, and front-running are the four patterns behind most real-world losses.
- The CEI pattern (checks, then effects, then interactions), the principle of least privilege, and fail-safe design are the highest-value, lowest-cost of the five secure-design principles covered here.
- Foundry, Hardhat, Slither, and OpenZeppelin Contracts form the standard practical toolchain; automated tools catch known patterns well, but business-logic-specific vulnerabilities still require human review.
Four common vulnerability patterns
Smart contract vulnerabilities are well enough catalogued to have a standard classification, the SWC (Smart Contract Weakness Classification). The following four patterns account for a large share of confirmed real-world losses.
- Reentrancy: an attack where, after a contract calls out to an external contract, that external call re-enters the original contract to withdraw balance again before it has been updated. This was the cause of The DAO hack, in which 3.6 million ETH (worth roughly JPY 6 billion at the time) was drained in 2016. Updating balances before making the external call — the CEI pattern — is the basic defense. Severity: high.
- Integer overflow/underflow: adding to a uint256 past its maximum wraps it back to zero (overflow), and subtracting below zero wraps it to the maximum value (underflow). Solidity 0.8.0 and later enable built-in overflow checks by default, but the problem can still occur inside an unchecked block. Severity: medium.
- Access-control gaps: when an important function lacks a proper access modifier, an attacker can perform actions equivalent to an administrator. Common patterns include a missing owner check, authentication based on tx.origin, and an access-control gap left in the constructor. Severity: high.
- Front-running: an attack that watches the mempool (unconfirmed transactions) to execute a more advantageous transaction ahead of a pending one. This is a particular problem for auctions, DEXs, and anything relying on on-chain randomness. Commit-reveal patterns and private mempools are the usual mitigations. Severity: medium.
The cost of finding a vulnerability is lowest during development, moderate during an audit, and highest after deployment. The standard flow is to build static analysis tools like Slither into CI as a quality gate, and to have a specialized audit firm review the contract before deployment.
Five principles of secure design
The goal is to design vulnerabilities out from the start, rather than fixing them afterward. The following five principles are widely adopted secure-design practices.
- CEI pattern (checks, effects, interactions): strictly enforce the order — check conditions, then update state, then make external calls — inside contract functions. Making the external call last prevents the great majority of reentrancy attacks.
- Principle of least privilege: grant each function and role only the minimum permissions it needs. Role-based management using OpenZeppelin's AccessControl is the standard way to implement this.
- Fail-safe design: build in a mechanism to pause the contract when an abnormal state is detected. Combining a Pausable pattern with an emergency-withdrawal path minimizes damage if an incident occurs.
- Clarity on upgradeability: decide before deployment whether to use a proxy-upgrade pattern. An immutable contract is easier to audit but cannot have bugs fixed later; an upgradeable design carries the risk of storage-slot conflicts.
- Pursuing full test coverage: combine unit tests, integration tests, and fuzzing to verify every state transition and boundary condition. Foundry's fuzzing feature can automatically generate edge cases that hand-written tests tend to miss.
Of the five, the CEI pattern and access control offer the best return for the lowest implementation cost, and are the highest priority. Upgradeability adds design complexity, so an immutable design is recommended unless it is a firm requirement.
The development toolchain
Smart contract security scales with how well these tools are used. Foundry, Hardhat, Slither, and OpenZeppelin are the four-tool standard configuration in practice.
- Foundry
- A fast, Rust-based testing framework. Supports Solidity-native tests, fuzz testing, and invariant testing, and is currently the most widely used tool in smart contract development.
- Hardhat
- A JavaScript/TypeScript-based development and testing environment, known for its rich plugin ecosystem and an easier on-ramp for developers already coming from JS. Being able to use console.log for debugging keeps the learning curve low.
- Slither
- A Python-based static analysis tool from Trail of Bits that automatically detects more than 80 vulnerability patterns. Wiring it into a CI pipeline gives you an automated security check before code review.
- OpenZeppelin Contracts
- An audited smart contract library implementing security best practices for ERC-20, ERC-721, AccessControl, Pausable, and more. Using proven, battle-tested code rather than writing your own reduces risk.
Automated tools are strong at catching known patterns, but vulnerabilities specific to your business logic still require human review. For contracts that handle assets, a code review by a specialized audit firm before deployment is recommended without exception.
The difficulty of secure design also depends on which chain you choose: EVM-compatible chains have the richest ecosystem of Solidity audit tooling and talent, while fewer audit firms are equipped to work on other chains.
Summary
The most common smart contract vulnerabilities are reentrancy, integer overflow, access-control gaps, and front-running. The standard security process is implementing the CEI pattern, least privilege, and fail-safe design at the design stage; testing and analyzing with Foundry and Slither; and commissioning a specialized audit before deployment. Using OpenZeppelin Contracts and building static analysis into CI eliminates known-pattern vulnerabilities at low cost — though none of this guarantees a contract is free of vulnerabilities, which is why an independent audit still matters.