The Stakes of Smart Contract Security
Smart contracts are programs that hold and transfer value. Unlike traditional software, bugs cannot typically be patched after deployment — vulnerabilities are exploited the moment they are discovered, often before developers can respond. The combination of immutability, public code, and real financial value makes smart contract security uniquely challenging.
Cumulative losses from smart contract exploits have exceeded $3 billion. Many of these exploits targeted well-known vulnerability patterns that have been documented for years. Understanding and avoiding common vulnerabilities is the first line of defense for any smart contract developer.
Reentrancy
Reentrancy occurs when a contract calls an external contract before updating its own state, allowing the external contract to call back into the original contract while it is in an intermediate state. The infamous 2016 DAO hack exploited reentrancy to drain 3.6 million ETH. Despite being a known vulnerability, reentrancy continues to cause significant losses.
Prevention: follow the checks-effects-interactions pattern religiously (verify conditions, update state, then make external calls), use reentrancy guards (mutex locks), and be particularly careful with any function that makes external calls or uses low-level call/delegatecall.
Flash Loan Attacks
Flash loans allow borrowing arbitrary amounts of tokens within a single transaction at zero cost, as long as the loan is repaid by the end of the transaction. Attackers use flash loans to temporarily acquire enough tokens to manipulate governance votes, oracle prices, or AMM pool prices to extract value.
Protocols vulnerable to flash loan attacks typically use spot prices for valuations (use TWAPs instead), allow governance actions in the same block as token acquisition (use time-weighted snapshot balances), or rely on pool reserves for price calculations without manipulation resistance.
Access Control
Access control vulnerabilities arise from missing or incorrect permission checks. Functions that should only be callable by the contract owner or specific authorized roles must have appropriate modifiers. The Poly Network hack ($611M) resulted from a missing check that allowed anyone to call a privileged function.
Use established access control patterns (OpenZeppelin's Ownable and AccessControl), apply the principle of least privilege, and conduct systematic reviews of every privileged function to verify that access restrictions are correct and comprehensive.
Integer Overflow and Underflow
Prior to Solidity 0.8.0, arithmetic operations did not check for overflow or underflow. Adding to the maximum uint value would wrap around to zero, and subtracting from zero would wrap to the maximum value. These bugs enabled attackers to set balances to arbitrarily large values or bypass balance checks.
Solidity 0.8.0 and above automatically reverts on arithmetic overflow/underflow. For older code or performance-sensitive code using unchecked blocks, explicitly use SafeMath or equivalent libraries.
Oracle Manipulation
Any contract that reads prices from an external oracle is vulnerable to oracle manipulation if the oracle can be influenced by the attacker. AMM spot prices are particularly vulnerable to manipulation within a single block using flash loans.
Use time-weighted average prices, multiple independent oracle sources, circuit breakers that reject prices deviating beyond expected bounds, and consider the specific manipulation attack surface for your protocol's use case.
The Audit Process
Professional security audits are mandatory for any contract managing significant value. A comprehensive audit typically takes two to four weeks for experienced teams and covers code review for known vulnerability patterns, business logic review for economic attack vectors, testing for edge cases, and comparison against specification.
Multiple audits from different firms with different methodologies provide stronger coverage. Bug bounty programs complement audits by continuously incentivizing security researchers to examine production code. Neither replaces the other — a multi-layered approach to security is required for high-value contracts.
Pre-Deployment Checklist
Before deploying to mainnet, every contract should pass through a systematic security checklist: comprehensive unit and integration test suite with high coverage, formal verification for critical invariants where feasible, at least one professional audit completed and findings addressed, testnet deployment and stress testing, internal security review by a team member not involved in original development, and a clear incident response plan for if vulnerabilities are discovered post-deployment.
The time and money invested in thorough security review is trivial compared to the potential cost of a successful exploit. In a space where protocol failures are public and permanent, security is not optional.