Smart Contract Auditing with Claude Code: A Security-First Workflow

Smart Contract Auditing with Claude Code: A Security-First Workflow

Smart Contract Auditing with Claude Code: A Security-First Workflow

Smart contract exploits drained over $1.9 billion from decentralized protocols in 2025. Access control flaws alone accounted for $953 million. Reentrancy attacks, a vulnerability class first exploited in 2016, still caused $35.7 million in losses last year. Developers are not lacking security awareness. The pace of DeFi deployment simply outstrips the availability of qualified auditors. A typical manual audit takes two to four weeks and costs $50,000 to $200,000. Most teams ship first and audit later, if they audit at all. AI-assisted auditing changes the equation. It does not replace human auditors, but it compresses the feedback loop from weeks to minutes, catching known vulnerability patterns before code ever reaches a reviewer’s desk. This article walks through a practical, security-first workflow for auditing Solidity contracts using Claude Code.

Why AI-Assisted Auditing Matters

The supply-demand imbalance in smart contract security is severe. Thousands of new contracts deploy to EVM chains every week. The pool of experienced auditors grows slowly. Contest platforms like Code4rena and Sherlock have expanded the talent pool, but competitive auditing introduces its own trade-offs: findings cluster around low-hanging fruit, and complex business logic bugs often go undetected.

AI acts as a force multiplier. A model like Claude can scan an entire codebase in seconds, flagging patterns that match known vulnerability classes. It does not get fatigued after reviewing the fifteenth transferFrom call, and it will not skip the helper library buried three directories deep. It can also run on every commit, not just before a mainnet deployment.

The key insight is positioning AI at the right point in the development lifecycle. Used during development, not as a post-hoc replacement for professional audits, AI catches 60-80% of common issues before they compound into complex, interacting vulnerabilities. The remaining 20-40% is where human expertise in novel attack vectors, economic modeling, and governance design becomes irreplaceable.

Setting Up Claude Code for Solidity

Claude Code works best when it has explicit context about what you expect it to do. For smart contract auditing, that means configuring a CLAUDE.md file at your project root with audit-specific instructions, and structuring your project so Claude can navigate it efficiently.

Start with a clean project layout:

my-protocol/
├── CLAUDE.md              # Audit instructions
├── contracts/
│   ├── core/
│   │   ├── Vault.sol
│   │   └── Router.sol
│   ├── interfaces/
│   │   └── IVault.sol
│   └── libraries/
│       └── MathLib.sol
├── test/
│   ├── Vault.t.sol
│   └── Router.t.sol
└── foundry.toml

The project structure matters because Claude Code uses file exploration tools to navigate your codebase. Flat directories with hundreds of files slow down context gathering. Group contracts by function — core logic, interfaces, libraries — so Claude can identify the attack surface quickly.

Install the Solidity extensions for your environment. If you are using Claude Code in a terminal, ensure forge (Foundry) is available in your PATH. Claude can invoke Foundry commands to compile contracts, run tests, and verify that suggested fixes do not break existing functionality.

# Verify Foundry is available
forge --version

# Compile contracts before starting audit
forge build

A successful compilation step is non-negotiable before auditing. Claude needs access to the compiled artifacts and the compiler warnings to provide accurate analysis.

The SCAR Workflow: Scan, Classify, Analyze, Report

Ad hoc prompting produces inconsistent audit results. A structured workflow produces repeatable, comprehensive coverage. The SCAR framework breaks smart contract auditing into four sequential phases, each with a clear input and output.

  • Scan — Automated detection of known vulnerability patterns across all contract files
  • Classify — Severity assignment using a standardized framework (Critical, High, Medium, Low, Informational)
  • Analyze — Deep-dive into each finding with execution path tracing, state change validation, and exploit scenario construction
  • Report — Structured output with findings, affected functions, recommended fixes, and test cases

Each phase builds on the previous one. Scanning without classification produces noise. Classification without analysis produces false confidence. Analysis without reporting produces tribal knowledge that lives in one developer’s head. The full pipeline turns Claude Code from a chatbot into an audit tool.

Step 1 — Automated Vulnerability Scanning

The scan phase targets known vulnerability classes from the OWASP Smart Contract Top 10. These are patterns with well-documented exploit histories and clear detection signatures.

Consider this simplified vault contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract SimpleVault {
    mapping(address => uint256) public balances;
    IERC20 public token;

    constructor(address _token) {
        token = IERC20(_token);
    }

    function deposit(uint256 amount) external {
        token.transferFrom(msg.sender, address(this), amount);
        balances[msg.sender] += amount;
    }

    function withdraw(uint256 amount) external {
        require(balances[msg.sender] >= amount, "Insufficient balance");

        // Vulnerability: state change after external call
        (bool success, ) = address(token).call(
            abi.encodeWithSelector(token.transfer.selector, msg.sender, amount)
        );
        require(success, "Transfer failed");

        balances[msg.sender] -= amount;
    }

    function emergencyWithdraw() external {
        uint256 amount = balances[msg.sender];
        balances[msg.sender] = 0;

        // This function is safe: state change before external call
        token.transfer(msg.sender, amount);
    }
}

When you ask Claude Code to scan this contract, it identifies the reentrancy vulnerability in withdraw(). The state update (balances[msg.sender] -= amount) happens after the external call (token.transfer). A malicious token contract could re-enter withdraw() before the balance is decremented, draining the vault.

Claude also correctly identifies that emergencyWithdraw() follows the Checks-Effects-Interactions pattern — state changes first, external call last — and is not vulnerable to reentrancy.

The scan phase covers these primary vulnerability classes:

  • Reentrancy: state changes after external calls, cross-function reentrancy, read-only reentrancy
  • Access control: missing onlyOwner modifiers, unprotected initialization functions, privilege escalation paths
  • Unchecked external calls: low-level .call() without return value checks, silent failures in token transfers
  • Oracle manipulation: spot price dependencies, TWAP windows that are too short, single-source price feeds
  • Integer issues: Solidity 0.8+ includes overflow protection, but unchecked blocks and casting between types still create risks
  • Front-running: sandwich-vulnerable swap calls, predictable state-dependent outcomes

Step 2 — Classify Severity

Raw scan results are not actionable without severity classification. A missing event emission and a reentrancy vulnerability in a vault holding $10 million TVL require fundamentally different response urgencies.

Claude applies a five-tier severity framework consistent with industry standards used by Immunefi and Code4rena:

Severity Criteria Example
Critical Direct loss of funds, no user interaction required Reentrancy in withdraw function
High Loss of funds with specific conditions, protocol-breaking state corruption Access control bypass on privileged function
Medium Conditional fund loss, griefing attacks, value leakage over time Front-runnable liquidation with MEV extraction
Low Best practice violations, minor inefficiencies with no direct fund risk Missing zero-address checks on constructor params
Informational Code quality, gas optimization, documentation gaps Unused import, inconsistent naming convention

For our SimpleVault example, Claude classifies the reentrancy in withdraw() as Critical: it allows direct fund extraction without special conditions beyond deploying a malicious contract. The low-level .call() usage compounds the risk because it forwards all available gas to the callee, giving an attacker ample execution budget for a re-entrant call.

Classification forces prioritization. Development teams with limited time should fix Critical and High findings before deployment. Medium findings warrant mitigation strategies. Low and Informational findings go into a backlog.

Step 3 — Deep Analysis

The analysis phase is where Claude Code adds the most value beyond simple pattern matching. Claude traces execution paths through multiple contracts, tracks state changes across function calls, and constructs concrete exploit scenarios.

Consider a more complex scenario where a router contract interacts with the vault:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./SimpleVault.sol";

contract Router {
    SimpleVault public vault;
    mapping(address => bool) public whitelisted;
    address public admin;

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    constructor(address _vault) {
        vault = SimpleVault(_vault);
        admin = msg.sender;
    }

    function setWhitelist(address user, bool status) external onlyAdmin {
        whitelisted[user] = status;
    }

    function routedDeposit(uint256 amount) external {
        require(whitelisted[msg.sender], "Not whitelisted");
        // Approves vault to spend router's tokens
        vault.token().approve(address(vault), amount);
        vault.deposit(amount);
    }

    // Missing: no onlyAdmin modifier
    function updateVault(address newVault) external {
        vault = SimpleVault(newVault);
    }
}

Claude identifies the missing access control on updateVault(). But the analysis goes deeper than flagging the missing modifier. Claude traces the impact chain:

  1. An attacker calls updateVault() with a malicious contract address
  2. The malicious contract implements the SimpleVault interface but redirects deposits
  3. When a whitelisted user calls routedDeposit(), the router approves the attacker’s contract to spend tokens
  4. The attacker drains approved tokens through the malicious vault

Cross-contract analysis is where AI auditing delivers the most value. A scanner checking Router.sol in isolation might flag the missing modifier as a Medium severity access control issue. Claude, with full project context, elevates it to Critical because it opens a path to indirect fund theft from whitelisted users.

Claude also validates business logic assumptions. If the protocol documentation states “only whitelisted users can deposit,” Claude checks whether that invariant holds across all entry points, not just the obvious ones. An AI agent interacting with these contracts would be equally vulnerable to a compromised router. This class of bug is particularly dangerous in autonomous commerce scenarios.

Step 4 — Generate Audit Report

The final phase produces a structured audit report. Unstructured findings scattered across chat messages are difficult to track and act on. Claude generates reports in a consistent format that maps to development team workflows.

Here is the report structure Claude produces for each finding:

## [CRITICAL] Reentrancy in SimpleVault.withdraw()

**Contract:** SimpleVault.sol
**Function:** withdraw(uint256 amount)
**Lines:** 20-28

### Description
The withdraw function performs an external call to the token contract
before updating the sender's balance. An attacker can deploy a contract
with a malicious fallback function that re-enters withdraw() before
the balance is decremented, draining the vault.

### Proof of Concept
1. Attacker deposits 1 ETH worth of tokens
2. Attacker calls withdraw(1 ETH) from a contract with a receive()
   function that calls withdraw(1 ETH) again
3. The re-entrant call succeeds because balances[attacker] has not
   been decremented yet
4. Repeat until vault is drained

### Recommended Fix
Apply the Checks-Effects-Interactions pattern. Update state before
making the external call:

    function withdraw(uint256 amount) external {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        token.transfer(msg.sender, amount);
    }

Alternatively, use OpenZeppelin's ReentrancyGuard:

    import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

### Test Case
    function test_reentrancy_withdraw() public {
        MaliciousReceiver attacker = new MaliciousReceiver(vault);
        token.transfer(address(attacker), 1 ether);
        attacker.attack();
        // Expect revert or controlled behavior after fix
    }

Each finding includes a test case that developers can drop into their Foundry test suite. This closes the loop: the finding comes with a verifiable proof and a regression test that prevents reintroduction.

For payment infrastructure contracts, like those powering payment monitoring systems or settlement layers, the report also flags operational risks: what happens if an admin key is compromised, what the maximum extractable value is in a single transaction, and whether time-locks provide adequate response windows.

Limitations and Human Oversight

AI-assisted auditing has real blind spots that teams must understand before relying on it.

Novel attack vectors. AI models are trained on historical data. A genuinely new attack class with no precedent in training data will not be flagged. The DAO hack was novel in 2016. Read-only reentrancy was novel in 2023. The next novel vector will bypass AI scanners until the models are retrained on examples of it.

Economic exploits. Many DeFi attacks are not bugs in the traditional sense. They are economically rational behaviors that the protocol designers did not anticipate. Flash loan attacks, governance manipulation, and MEV extraction often involve perfectly valid contract interactions. Claude can reason about these if prompted, but it does not inherently model market dynamics or game theory.

Cross-protocol composability. A contract that is secure in isolation may be exploitable when composed with other protocols. If your vault integrates with Aave, Uniswap, and a custom oracle, the interaction surface grows combinatorially. Claude can analyze contracts it can see, but it cannot audit the deployed bytecode of third-party dependencies in real time.

Formal verification gaps. AI auditing is heuristic, not formal. It does not provide mathematical proofs of correctness. For contracts managing significant TVL, pair AI auditing with formal verification tools like Certora or Halmos to cover properties that require provable guarantees.

The recommended approach: use Claude Code for continuous development-phase auditing, engage a professional audit firm for pre-deployment review, and maintain a bug bounty program for post-deployment coverage. AI handles breadth and speed, while humans handle depth and novelty. The most secure protocols in 2026 use all three layers together.

CLAUDE.md Template for Smart Contract Audits

The following template configures Claude Code for smart contract auditing. Save it as CLAUDE.md in your project root. Adapt the scope, severity definitions, and focus areas to your protocol.

# Smart Contract Audit Configuration

## Role
You are a senior smart contract security auditor. Your task is to
identify vulnerabilities, assess severity, and recommend fixes for
all Solidity contracts in this project.

## Audit Scope
- All files in contracts/core/ and contracts/libraries/
- Interfaces in contracts/interfaces/ are reference-only
- Test files are out of scope for vulnerability assessment

## Methodology: SCAR
Follow this sequence for every audit session:
1. **Scan** all in-scope contracts for known vulnerability patterns
2. **Classify** each finding by severity (Critical/High/Medium/Low/Info)
3. **Analyze** Critical and High findings with execution path tracing
4. **Report** all findings in the structured format below

## Vulnerability Checklist
Scan for these patterns in every contract:
- [ ] Reentrancy (state changes after external calls)
- [ ] Access control (missing modifiers, unprotected init)
- [ ] Unchecked external calls (low-level .call without checks)
- [ ] Integer issues (unchecked blocks, unsafe casting)
- [ ] Oracle manipulation (spot prices, short TWAP windows)
- [ ] Front-running (sandwich-vulnerable operations)
- [ ] Denial of service (unbounded loops, block gas limit)
- [ ] Timestamp dependence (block.timestamp manipulation)
- [ ] tx.origin authentication
- [ ] Delegatecall to untrusted contracts

## Severity Definitions
- **Critical**: Direct fund loss, no preconditions
- **High**: Fund loss with specific conditions, state corruption
- **Medium**: Conditional loss, griefing, value leakage
- **Low**: Best practice violations, no direct fund risk
- **Informational**: Code quality, gas optimization

## Report Format
For each finding, provide:
1. Severity tag and title
2. Affected contract, function, and line numbers
3. Description of the vulnerability
4. Step-by-step proof of concept
5. Recommended fix with code
6. Foundry test case for regression testing

## Rules
- Never skip a contract file, even if it looks simple
- Always check cross-contract interactions
- Flag any function that can be called by arbitrary addresses
- If a finding is uncertain, mark it as "Needs Manual Review"
- After completing the audit, summarize: total findings by severity,
  overall risk assessment, and top 3 recommendations

This template encodes the SCAR methodology directly into Claude’s context. When you open your project in Claude Code, it loads these instructions automatically and applies them consistently across audit sessions. You can extend it with protocol-specific invariants — for example, “the total supply of vault shares must always equal the sum of all user deposits” — to catch business logic violations unique to your protocol.

For teams building MCP-integrated payment systems, add a section covering payment-specific risks: double-spend scenarios, settlement finality checks, and refund logic edge cases. The template is a living document that improves with every audit cycle.

If you are new to using Claude Code for blockchain development more broadly, the Web3 development guide covers the foundational setup, project configuration, and workflow patterns that complement this audit-focused approach.

Production-Grade Smart Contract Security

AI auditing is a strong first pass, but production contracts need professional review. Aurpay’s smart contract service provides comprehensive audits for payment infrastructure, DeFi protocols, and token contracts. Request an audit.

Ricky

Growth Strategist at Aurpay

As a growth strategist at Aurpay, Ricky is dedicated to removing the friction between traditional commerce and blockchain technology. He helps merchants navigate the complex landscape of Web3 payments, ensuring seamless compliance while executing high-impact marketing campaigns. Beyond his core responsibilities, he is a relentless experimenter, constantly testing new growth tactics and tweaking product UX to maximize conversion rates and user satisfaction

Sign Up for Our Newsletter

Get the latest crypto news and updates from the experts at Aurpay.