HomeLearning pathMulti-sig walletsSmart contract auditingPhishing awarenessVerify team member
Start learning

Smart contract auditing

A comprehensive guide to securing your protocol through professional code review -- from choosing the right audit firms to understanding what they look for and how to prepare.

25 min read
Advanced
Updated Feb 2026

Why audit smart contracts

Smart contracts are immutable by design. Once deployed to a blockchain, their code becomes the definitive source of truth -- bugs included. Unlike traditional software where a patch can be pushed in hours, a vulnerability in a live smart contract can drain millions of dollars before anyone has time to react. This fundamental reality makes pre-deployment auditing not just a best practice, but a survival requirement.

$3.8B+
Lost to smart contract exploits (2022-2024)
$60M
Drained in The DAO hack (2016)
$325M
Stolen from Wormhole bridge (2022)
80%
Of exploits were in unaudited code

The DAO hack: the catalyst

In June 2016, The DAO -- the first major decentralized autonomous organization on Ethereum -- was exploited for approximately 3.6 million ETH (roughly $60 million at the time). The attacker exploited a reentrancy vulnerability, a bug class that would have been caught by any competent audit firm today. The exploit was so devastating that the Ethereum community controversially decided to hard-fork the entire blockchain to reverse the theft, creating Ethereum Classic in the process.

This single event fundamentally changed the industry's attitude toward security. It proved that "code is law" only works when the code is correct.

Wormhole bridge exploit

In February 2022, an attacker exploited a vulnerability in the Wormhole bridge's Solana-side smart contracts. The bug allowed the attacker to mint 120,000 wETH (wrapped Ether) on Solana without depositing equivalent ETH on Ethereum. Jump Crypto, the parent company, ultimately covered the $325 million loss. The vulnerability was in a signature verification function that failed to properly validate guardian signatures -- a critical access control flaw.

The Cost of Skipping Audits

The average cost of a smart contract audit is $50,000 to $500,000. The average cost of a smart contract exploit is $15 million. Projects that skip audits to save money are making a statistically catastrophic bet -- a 100x potential loss to save a fraction of their treasury.

More than just financial loss

The impact of an unaudited or poorly audited contract goes beyond the immediate financial damage:

  • Protocol death: Many exploited protocols never recover. Users lose trust and TVL evaporates permanently.
  • Legal liability: As regulatory frameworks mature, deploying unaudited financial contracts may constitute negligence in multiple jurisdictions.
  • Ecosystem damage: Each exploit erodes trust in DeFi broadly, hurting adoption for the entire space.
  • Team reputation: Founders and developers associated with exploited protocols face lasting career consequences.

The three-audit minimum

One audit is better than none, but it is far from sufficient. The industry standard for any protocol managing significant value is a minimum of three independent audits from different firms. This is not marketing -- it is grounded in statistical reasoning and practical experience.

Why one audit falls short

Every audit firm has inherent biases and blind spots. Their effectiveness depends on the tools they use, the experience of their individual auditors, and their particular areas of expertise. A single firm might excel at catching reentrancy bugs but miss subtle oracle manipulation vectors. Another might be world-class at formal verification but overlook business logic errors.

The Statistical Argument

If a single audit firm has a 90% probability of catching a critical vulnerability (an optimistic estimate), then a single audit leaves a 10% chance of that bug shipping to production. Two independent audits reduce that probability to 1% (0.1 x 0.1). Three audits bring it down to 0.1%. For protocols managing hundreds of millions in TVL, that difference between 10% and 0.1% is the difference between eventual exploitation and robust security.

Diversity of methodology

Each audit firm brings a fundamentally different approach to the table:

  • Manual review depth: Some firms allocate 80% of their time to line-by-line manual review, while others lean more heavily on automated tooling.
  • Tool coverage: Slither, Mythril, Echidna, Manticore, Certora, and proprietary tools each find different classes of bugs. No single tool catches everything.
  • Domain expertise: A firm specializing in DeFi lending protocols will catch issues that a generalist firm misses, and vice versa for NFT marketplaces or cross-chain bridges.
  • Adversarial mindset: Firms with offensive security backgrounds (penetration testing, red teaming) think about attacks differently than firms rooted in formal methods.

The ideal audit stack

Start with a well-established firm that excels at comprehensive coverage. They will find the most common vulnerability classes and validate the overall architecture. OpenZeppelin is a strong choice for this first pass, as they have deep experience across protocol types and will identify structural issues early.

The second audit should come from a firm that approaches your code from an attacker's perspective. HYDN's red team background and penetration testing methodology complement traditional code review by testing how your protocol holds up against real-world attack patterns, including threats beyond the smart contract layer.

The third audit should use a fundamentally different methodology from the first two. If the first two audits were primarily manual review, the third should emphasize formal verification or property-based testing. If the protocol handles very large values, consider firms that use mathematical proofs (such as Certora or Runtime Verification) to verify invariants hold under all possible conditions.

Recommended audit firms

Selecting the right audit firms is one of the most consequential decisions a protocol team will make. Below are the two firms we recommend and work with directly.

OpenZeppelin

Industry standard

Methodology: Deep manual review combined with their proprietary Defender platform for ongoing monitoring. Their auditors follow a structured process: architecture review, threat modeling, line-by-line code analysis, and automated scanning. Reports are among the most detailed in the industry.

Notable clients: Compound, Aave, The Ethereum Foundation, Coinbase, USDC (Circle). Their open-source contract library is used by over 30,000 projects.

Strengths: DeFi protocols, token standards, governance systems, upgradeability patterns. They literally wrote the book on secure Solidity development with their widely-adopted OpenZeppelin Contracts library.

Best for: Teams building core DeFi primitives, token launches, or projects using OpenZeppelin's contract library who want auditors deeply familiar with the underlying code.

HYDN

Offensive security

Methodology: HYDN combines in-depth smart contract auditing with advanced adversarial simulation (red teaming) and web3 penetration testing. With over 40 years of combined cybersecurity experience, their team assesses safety, functionality, and protection from an attacker's perspective. They specialize in EVM-compatible blockchains.

Notable clients: MetaMask, Bittrex, Sablier, and a16z-backed projects. Their red team has decades of experience fighting APT groups including Lazarus Group.

Strengths: Full-stack security beyond just smart contracts -- web3 penetration testing, adversarial simulation, blockchain consulting, and secure architecture design. Built for organizations that cannot afford to get security wrong.

Best for: Projects that need holistic security covering smart contracts, infrastructure, and operational security. Particularly strong for teams facing nation-state-level threats.

Discounted audits through Metron

We work directly with both OpenZeppelin and HYDN. Projects referred through Metron receive additional discounts on audit engagements. Get in touch to learn more about our referral program and how we can help you get the best rate for your audit.

The audit process

A professional smart contract audit follows a structured, multi-phase process. Understanding each phase helps teams prepare effectively and set realistic expectations for timelines and deliverables.

1
Scoping
2
Engagement
3
Review
4
Report
5
Remediation
6
Re-audit

The audit firm reviews your codebase to estimate the effort required. They assess lines of code, contract complexity, external integrations, and the number of auditor-weeks needed. You will receive a proposal with cost, timeline, and team composition. During scoping, the firm may ask questions about your architecture, intended behavior, and known risks.

Your deliverables: Repository access, documentation, deployment scripts, and a clear description of what is in scope versus out of scope.

A kickoff call between your development team and the audit team. The auditors walk through the architecture with your engineers, ask clarifying questions, and align on communication channels. The specific commit hash to be audited is locked at this point -- no further code changes should be made during the audit window.

Key outcome: Both teams have a shared understanding of the system, threat model, and communication expectations. A shared Slack channel or similar real-time communication channel is established for questions during the review.

The core audit work happens here. Auditors perform manual line-by-line review, run automated analysis tools, write custom fuzz tests, and attempt to find exploitable vulnerabilities. Most firms assign 2-4 auditors who work independently before comparing findings to reduce blind spots.

During this phase, auditors may reach out with questions about intended behavior. Respond promptly -- auditor questions often indicate they are investigating a potential issue and a quick answer helps them determine if it is a real vulnerability or intended behavior.

The audit firm delivers a comprehensive report detailing all findings, categorized by severity (Critical, High, Medium, Low, Informational). Each finding includes a description, proof of concept or exploit scenario, affected code, and recommended fix. The report also typically includes an executive summary, methodology description, and overall assessment.

Severity levels:

  • Critical: Direct loss of funds or permanent denial of service. Must be fixed before deployment.
  • High: Significant risk of fund loss under specific conditions or major functionality break.
  • Medium: Limited risk of fund loss, unexpected behavior, or governance concerns.
  • Low: Best practice violations, gas optimizations, or minor issues with no direct security impact.
  • Informational: Code quality suggestions, documentation improvements, or notes for future consideration.

Your development team addresses each finding. For each issue, you either implement the recommended fix, implement an alternative fix (with justification), or acknowledge the risk and document why it is accepted. All critical and high-severity findings should be fixed. Medium findings should be fixed where practical. Low and informational findings are at your discretion.

Important: Do not introduce new features during remediation. Only fix the reported issues and related code. New functionality requires a new audit scope.

The audit firm reviews your fixes to verify they correctly address the reported issues without introducing new vulnerabilities. This phase is typically included in the original engagement cost for a single round of fixes. The final report is updated with the remediation status of each finding (Fixed, Acknowledged, or Partially Fixed).

The final, public-facing report is produced after this phase. Many protocols publish their audit reports for transparency, which is considered a strong trust signal.

What auditors look for

Smart contract auditors examine code for a wide range of vulnerability classes. Below are the most common and dangerous categories, along with Solidity code examples that illustrate how these bugs manifest in practice.

Reentrancy attacks

Reentrancy is the most infamous class of smart contract vulnerability. It occurs when a contract makes an external call to another contract before updating its own state, allowing the called contract to "re-enter" the original function and exploit the stale state.

// VULNERABLE: State update happens AFTER external call contract VulnerableVault { mapping(address => uint256) public balances; function withdraw() external { uint256 amount = balances[msg.sender]; require(amount > 0, "No balance"); // External call BEFORE state update -- attacker re-enters here (bool success, ) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); // This line never executes during reentrancy balances[msg.sender] = 0; } }
// SECURE: Checks-Effects-Interactions pattern contract SecureVault { mapping(address => uint256) public balances; function withdraw() external { uint256 amount = balances[msg.sender]; require(amount > 0, "No balance"); // State update BEFORE external call balances[msg.sender] = 0; (bool success, ) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); } }
Cross-Function Reentrancy

Modern reentrancy attacks are more subtle than the classic example above. Cross-function reentrancy exploits shared state between multiple functions. Read-only reentrancy targets view functions used by other protocols. Always use a reentrancy guard (like OpenZeppelin's ReentrancyGuard) in addition to the Checks-Effects-Interactions pattern.

Integer overflow / underflow

Before Solidity 0.8.0, arithmetic operations silently wrapped around on overflow and underflow. While Solidity 0.8+ includes built-in overflow checks, contracts using unchecked blocks or older compiler versions remain vulnerable.

// VULNERABLE (Solidity <0.8.0 or unchecked blocks) contract TokenSale { mapping(address => uint256) public balances; function transfer(address to, uint256 amount) external { // If balances[msg.sender] is 0 and amount is 1: // 0 - 1 = 2^256 - 1 (underflow!) unchecked { balances[msg.sender] -= amount; balances[to] += amount; } } }
// SECURE: Use Solidity 0.8+ default checked arithmetic contract TokenSale { mapping(address => uint256) public balances; function transfer(address to, uint256 amount) external { require(balances[msg.sender] >= amount, "Insufficient balance"); balances[msg.sender] -= amount; // Reverts on underflow in 0.8+ balances[to] += amount; // Reverts on overflow in 0.8+ } }

Access control issues

Missing or incorrect access control is one of the most common vulnerability classes. Functions that should be restricted to administrators or specific roles are left publicly callable, allowing attackers to execute privileged operations.

// VULNERABLE: No access control on critical function contract VulnerableVault { address public owner; mapping(address => uint256) public balances; // Anyone can call this and set themselves as owner! function initialize(address _owner) external { owner = _owner; } // Missing onlyOwner modifier function emergencyWithdraw() external { payable(msg.sender).transfer(address(this).balance); } }
// SECURE: Proper access control with initializer guard import "@openzeppelin/contracts/access/Ownable.sol"; contract SecureVault is Ownable { bool private initialized; function initialize(address _owner) external { require(!initialized, "Already initialized"); initialized = true; _transferOwnership(_owner); } function emergencyWithdraw() external onlyOwner { payable(owner()).transfer(address(this).balance); } }

Oracle manipulation

DeFi protocols that rely on price oracles are vulnerable to manipulation if they use a single price source or a spot price that can be moved within a single transaction. Attackers exploit this by artificially moving the oracle price (e.g., via a large swap) and then interacting with the vulnerable protocol at the manipulated price.

// VULNERABLE: Using spot price from a single DEX contract VulnerableLending { IUniswapV2Pair pair; function getPrice() public view returns (uint256) { // Spot price can be manipulated in a single tx (uint112 reserve0, uint112 reserve1, ) = pair.getReserves(); return (uint256(reserve1) * 1e18) / uint256(reserve0); } }
// SECURE: Use Chainlink oracle with staleness checks import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; contract SecureLending { AggregatorV3Interface internal priceFeed; uint256 constant STALENESS_THRESHOLD = 3600; // 1 hour function getPrice() public view returns (uint256) { (, int256 price, , uint256 updatedAt, ) = priceFeed.latestRoundData(); require(price > 0, "Invalid price"); require(block.timestamp - updatedAt < STALENESS_THRESHOLD, "Stale price"); return uint256(price); } }

Flash loan attacks

Flash loans allow users to borrow massive amounts of capital with zero collateral, as long as the loan is repaid within the same transaction. Attackers use this capital to amplify other attack vectors -- particularly oracle manipulation, governance attacks, and arbitrage exploits.

// ATTACK PATTERN: Flash loan + oracle manipulation // 1. Borrow $100M via flash loan from Aave // 2. Dump token on Uniswap, crashing the spot price // 3. Borrow at the artificially low price on vulnerable lending protocol // 4. Price recovers, profit from the spread // 5. Repay flash loan + fee // // Defense: Never use spot prices. Use TWAPs or Chainlink oracles. // Defense: Add minimum borrow delays (prevents same-block exploitation). // Defense: Implement circuit breakers for abnormal price movements.

Front-running / MEV

Maximal Extractable Value (MEV) refers to the profit that block builders and searchers can extract by reordering, inserting, or censoring transactions within a block. Front-running is the most common MEV strategy, where an attacker observes a pending transaction in the mempool and submits their own transaction with higher gas to execute first.

// VULNERABLE: Predictable swap with no slippage protection function swapTokens(uint256 amountIn) external { // No minimum output -- sandwich attack guaranteed router.swapExactTokensForTokens( amountIn, 0, // amountOutMin = 0, accepts ANY output path, msg.sender, block.timestamp ); }
// SECURE: Slippage protection + deadline function swapTokens( uint256 amountIn, uint256 amountOutMin, // User-specified minimum uint256 deadline // Transaction expiry ) external { require(block.timestamp <= deadline, "Expired"); router.swapExactTokensForTokens( amountIn, amountOutMin, // Revert if output below threshold path, msg.sender, deadline ); }
Beyond These Six Categories

Professional auditors also check for: storage collision in proxy patterns, denial of service vectors, signature replay attacks, timestamp dependence, tx.origin authentication, unchecked return values, gas griefing, and logic errors specific to your protocol's business rules. The categories above represent the most frequently exploited classes, not the complete list.

Preparing for an audit

The quality of your audit directly correlates with how well you prepare. A well-prepared codebase means auditors spend their time finding real vulnerabilities instead of deciphering your code. Poor preparation leads to wasted auditor-hours, lower coverage, and a less valuable report.

Documentation requirements

  • Architecture overview: A high-level document describing the system's components, how they interact, and the intended flow of funds. Diagrams are invaluable.
  • Specification document: Detailed description of what each contract and function is supposed to do. Auditors compare actual behavior against your specification to find logic bugs.
  • Known risks and trade-offs: Document any design decisions where you chose to accept a risk. This prevents auditors from spending time on issues you already know about.
  • External dependencies: List all oracles, bridges, tokens, and protocols your contracts interact with, including their trust assumptions.
  • Deployment plan: Describe how contracts will be deployed, initialized, and configured. Many exploits occur during deployment, not in the contract logic itself.
  • Access control matrix: A clear table showing which roles can call which functions. This is essential for auditors to verify permissions are correctly implemented.

Test coverage

Auditors will look at your test suite as a signal of code quality and to understand intended behavior. Aim for the following minimums before submitting your code for audit:

Coverage TypeMinimum TargetWhy It Matters
Line coverage90%+Ensures all code paths have been exercised at least once
Branch coverage85%+Verifies both sides of every conditional statement are tested
Integration testsAll critical flowsTests contracts interacting with each other, not just in isolation
Fuzz testsCore invariantsProperty-based tests that run thousands of random inputs to find edge cases
Fork testsExternal integrationsTests against mainnet forks to verify behavior with real external contracts

Code freeze practices

One of the most critical preparation steps is a proper code freeze before the audit begins:

  • Lock the commit hash: The audit is performed against a specific commit. No changes should be made to audited code during the review window.
  • Resolve all TODOs: Leftover TODO comments signal incomplete code. Auditors cannot effectively review code that the developers themselves consider unfinished.
  • Remove dead code: Unused functions, commented-out blocks, and experimental features increase the audit surface area without adding value. Remove them.
  • Run all linters and formatters: Clean, consistently formatted code is easier to audit. Run solhint, prettier-plugin-solidity, and your formatter of choice.
  • Compile with zero warnings: Compiler warnings often indicate real issues. Resolve all of them before submitting for audit.
Pre-Audit Checklist

Before sending your code to an audit firm, verify: (1) all tests pass, (2) documentation is current, (3) NatSpec comments are on all public/external functions, (4) you have run Slither or a similar static analyzer and addressed its findings, and (5) your team has done an internal review. This preparation typically saves 20-30% of audit costs by reducing the time auditors spend on obvious issues.

After the audit

An audit report is a snapshot in time, not a permanent guarantee of security. The work of securing your protocol continues well after the final report is published. The most resilient protocols treat security as an ongoing process, not a one-time checkbox.

Bug bounty programs

Launching a bug bounty program immediately after deployment creates a continuous security review by the broader community. Platforms like Immunefi specialize in Web3 bug bounties and provide the infrastructure to manage submissions, triage reports, and pay bounties.

  • Set meaningful bounties: A critical vulnerability bounty should be 5-10% of the total value at risk, up to a reasonable cap. Bounties that are too low will not attract serious researchers.
  • Define clear scope: Specify exactly which contracts and which vulnerability types are in scope. Provide the same documentation you gave your auditors.
  • Respond quickly: Researchers expect acknowledgment within 48 hours and triage within a week. Slow response times drive talent away from your program.
  • Pay promptly: Researchers talk to each other. A reputation for fair, prompt payment attracts the best talent.

On-chain monitoring

Deploy monitoring systems that watch your contracts for anomalous behavior in real-time. Key signals to monitor include:

  • Unusual transaction patterns: Spikes in transaction volume, abnormally large transfers, or rapid repeated function calls.
  • Oracle deviations: Price feeds that deviate significantly from expected ranges or show sudden jumps.
  • Governance proposals: Unexpected proposals, votes from newly acquired tokens, or proposals submitted immediately after large token purchases.
  • Contract upgrades: Unauthorized proxy upgrades or admin key usage outside of expected operational patterns.

Tools like OpenZeppelin Defender, Forta, and Tenderly provide monitoring and alerting capabilities specifically designed for smart contract operations.

Upgrade patterns

For protocols that use upgradeable proxy patterns (UUPS, Transparent Proxy, Beacon), each upgrade introduces new code that requires its own security review. Best practices include:

  • Timelock on upgrades: A minimum 48-hour (ideally 7-day) delay between an upgrade proposal and execution, giving the community time to review and react.
  • Upgrade audits: Every upgrade should be audited, even if the changes seem minor. Storage layout changes in particular can cause catastrophic bugs in proxy patterns.
  • Multisig control: Upgrade authority should be held by a multisig wallet (3-of-5 minimum), not a single EOA (externally owned account).
  • Emergency procedures: Document and drill your emergency response plan. Know exactly who needs to sign what, and in what order, to pause the protocol or execute an emergency fix.

Cost & timeline guide

Audit costs vary significantly based on codebase complexity, firm reputation, and market demand. The following ranges represent typical pricing as of early 2026. During bull markets, prices and wait times tend to increase as more projects compete for limited auditor bandwidth.

Protocol ComplexityLines of SolidityTypical DurationCost Range
Simple Token / NFT200 - 5001 - 2 weeks$10,000 - $30,000
Basic DeFi (Staking, Vesting)500 - 1,5002 - 3 weeks$30,000 - $80,000
Medium DeFi (DEX, Lending)1,500 - 4,0003 - 5 weeks$80,000 - $200,000
Complex DeFi (Derivatives, Bridges)4,000 - 10,0005 - 8 weeks$200,000 - $500,000
Protocol Suite (Full Ecosystem)10,000+8 - 16 weeks$500,000 - $1,500,000+

Factors that affect pricing

Lines of code is the baseline metric, but complexity matters more. A 2,000-line contract with intricate mathematical formulas, assembly blocks, and cross-contract interactions will cost more to audit than a 5,000-line contract with straightforward CRUD operations. Novel mechanisms that have not been audited before (new bonding curve designs, exotic options, etc.) command premium pricing because auditors cannot rely on patterns from prior engagements.

Top-tier firms (OpenZeppelin, HYDN) command premium rates and often have wait times of 2-6 months. Their reports carry significant weight with investors and the community, which can justify the premium. Referral programs (like ours at Metron) can help reduce costs while maintaining access to top-tier auditors.

Rush audits (requesting priority scheduling) typically carry a 25-50% premium over standard pricing. Some firms offer expedited timelines where they allocate additional auditors to compress the review period. Plan ahead to avoid rush fees -- ideally, book your audit slot 2-3 months before your target deployment date.

Well-documented code with comprehensive test suites reduces the time auditors spend understanding your system, directly lowering the cost. Conversely, poorly documented code with minimal tests increases audit time and cost, because auditors must reverse-engineer intent from the code itself. Some firms offer discounts for projects that meet their documentation and testing standards.

Auditing Solana (Rust), Cosmos (Go), or Move-based contracts (Aptos, Sui) typically costs more than EVM audits due to the smaller pool of qualified auditors. Multi-chain deployments that require auditing the same protocol across multiple VMs further increase costs. Bridges and cross-chain messaging protocols are among the most expensive to audit due to the expanded attack surface.

Budget for Three Audits

When planning your security budget, multiply the single-audit cost by three and add 20% for bug bounty program funding. A medium-complexity DeFi protocol should budget $300,000 to $600,000 total for security. This sounds expensive until you compare it to the average exploit loss. Security is the highest-ROI investment a protocol can make.

Reducing costs without sacrificing quality

  • Start with audit competitions: Platforms like Code4rena and Sherlock run competitive audits at lower costs than traditional firms. Use these as your first pass before engaging a top-tier firm.
  • Invest in internal review: A thorough internal security review before the audit reduces the number of easy findings, letting the paid auditors focus on deeper issues.
  • Minimize scope: Only include finalized, production-ready code in the audit scope. Remove experimental features, test contracts, and deployment scripts that do not need review.
  • Build on audited primitives: Using well-audited libraries (OpenZeppelin Contracts, Solmate) means the auditors only need to review your custom logic, not battle-tested building blocks.
  • Book early: Firms offer better rates and availability when booked well in advance. Last-minute engagements during market peaks can be 2-3x the normal price.