Audit Solidity Smart Contracts with AI in 20 Minutes

Find critical vulnerabilities in Solidity code using AI tools like Claude and GPT-4. Catch reentrancy, overflow, and access control bugs before deployment.

Problem: Manual Audits Miss Critical Vulnerabilities

You're deploying a Solidity contract handling real funds, but manual code review missed a reentrancy vulnerability that could drain your protocol.

You'll learn:

  • How to use AI for systematic vulnerability scanning
  • Which attack patterns AI catches vs. misses
  • How to combine AI with traditional tools for production readiness

Time: 20 min | Level: Intermediate


Why This Happens

Smart contract audits require checking for dozens of vulnerability patterns across complex codebases. Human reviewers focus on business logic and miss subtle patterns like:

Common blind spots:

  • Reentrancy with non-obvious external calls
  • Integer overflow in Solidity <0.8.0
  • Access control bypasses in multi-contract systems
  • Front-running vulnerabilities in DeFi protocols

AI models trained on exploit databases can pattern-match these systematically.


Solution

Step 1: Prepare Your Contract for Analysis

# Install dependencies
npm install --save-dev @openzeppelin/contracts
forge install foundry-rs/forge-std

# Compile to catch syntax issues first
forge build

Expected: Clean compilation. Fix compiler errors before AI analysis.

If it fails:

  • Error: "Solidity version mismatch": Update foundry.toml to match your pragma

Step 2: Create an AI Audit Prompt

# Save as audit-prompt.md

Analyze this Solidity contract for vulnerabilities. Focus on:

1. **Reentrancy:** External calls that allow recursive re-entry
2. **Access Control:** Functions missing proper authorization
3. **Integer Issues:** Overflow/underflow (if Solidity <0.8.0)
4. **Front-Running:** Transaction ordering dependencies
5. **Gas Optimization:** Unnecessary SLOAD operations

For each issue:
- Severity: Critical | High | Medium | Low
- Line numbers
- Exploit scenario
- Recommended fix

Contract:

Why this works: Structured prompts get specific, actionable results instead of generic security advice.


Step 3: Run AI Analysis with Claude or GPT-4

# Using Claude API (example with Python)
cat > audit.py << 'EOF'
import anthropic
import os

client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))

# Read your contract
with open("src/MyContract.sol", "r") as f:
    contract_code = f.read()

with open("audit-prompt.md", "r") as f:
    prompt = f.read()

message = client.messages.create(
    model="claude-sonnet-4-20250514",  # Best for code analysis
    max_tokens=4000,
    messages=[
        {"role": "user", "content": f"{prompt}\n\n```solidity\n{contract_code}\n```"}
    ]
)

# Save audit report
with open("audit-report.md", "w") as f:
    f.write(message.content[0].text)

print("✓ Audit complete. Check audit-report.md")
EOF

python audit.py

Expected: AI returns structured findings with severity ratings.


Step 4: Verify AI Findings with Static Analysis

# Install Slither (Trail of Bits tool)
pip install slither-analyzer --break-system-packages

# Run automated checks
slither . --exclude-dependencies

# Compare with AI findings
diff <(grep -o "Line [0-9]*" audit-report.md | sort) \
     <(slither . --json - | jq '.results[].check' | sort)

Why both tools: AI catches logic flaws, Slither catches known patterns. Use both.

If it fails:

  • Slither reports false positives: Check if AI agrees. False positives common in proxy patterns.

Step 5: Analyze a Real Example

Here's a vulnerable contract AI should catch:

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

contract VulnerableBank {
    mapping(address => uint256) public balances;
    
    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
    
    // ❌ CRITICAL: Reentrancy vulnerability
    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        
        // External call BEFORE state update
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        
        balances[msg.sender] -= amount;  // Too late!
    }
}

AI should identify:

**CRITICAL: Reentrancy in withdraw() - Line 15**

Severity: Critical
Impact: Complete fund drainage

Exploit:
1. Attacker calls withdraw()
2. Fallback function re-enters withdraw()
3. Balance check passes (not updated yet)
4. Process repeats until contract drained

Fix:
- Move balance update before external call (Checks-Effects-Interactions pattern)
- Or use ReentrancyGuard from OpenZeppelin

Corrected version:

function withdraw(uint256 amount) public {
    require(balances[msg.sender] >= amount, "Insufficient balance");
    
    // Update state FIRST
    balances[msg.sender] -= amount;
    
    // Then make external call
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success, "Transfer failed");
}

Step 6: Test the Fix

// test/VulnerableBank.t.sol
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/VulnerableBank.sol";

contract Attacker {
    VulnerableBank public bank;
    uint256 public attackCount;
    
    constructor(address _bank) {
        bank = VulnerableBank(_bank);
    }
    
    receive() external payable {
        // Try to re-enter (should fail with fixed version)
        if (attackCount < 3) {
            attackCount++;
            bank.withdraw(1 ether);
        }
    }
    
    function attack() public payable {
        bank.deposit{value: msg.value}();
        bank.withdraw(1 ether);
    }
}

contract VulnerableBankTest is Test {
    VulnerableBank public bank;
    
    function testReentrancyPrevented() public {
        bank = new VulnerableBank();
        Attacker attacker = new Attacker(address(bank));
        
        // Fund bank
        vm.deal(address(bank), 10 ether);
        
        // Attacker deposits 1 ETH
        vm.deal(address(attacker), 1 ether);
        attacker.attack{value: 1 ether}();
        
        // With fix: attacker should only withdraw once
        assertEq(address(bank).balance, 10 ether);  // Bank funds safe
    }
}
# Run test
forge test --match-test testReentrancyPrevented -vvv

# Should pass with fixed version

Verification

Run complete audit workflow:

# 1. AI analysis
python audit.py

# 2. Static analysis
slither . --exclude-dependencies

# 3. Automated tests
forge test

# 4. Generate coverage report
forge coverage --report summary

You should see:

  • AI report with prioritized findings
  • Slither confirmation of critical issues
  • 100% test coverage on fixed functions
  • No critical vulnerabilities remaining

What You Learned

AI strengths:

  • Logic flaws in business code (auction rigging, voting manipulation)
  • Complex reentrancy patterns across multiple contracts
  • Explaining WHY code is vulnerable (not just flagging)

AI limitations:

  • Doesn't verify on-chain bytecode matches source
  • May miss novel attack vectors (zero-days)
  • Can't assess economic attack feasibility

When NOT to rely solely on AI:

  • High-value protocols (>$10M TVL) need human auditors
  • Novel DeFi mechanics (AI trained on existing exploits)
  • Contracts with upgradability or governance

Production checklist:

  1. AI audit (this guide)
  2. Slither/Mythril automated tools
  3. Unit tests with >90% coverage
  4. Professional audit firm (for mainnet)
  5. Bug bounty program post-launch

Real-World AI Audit Workflow

# Complete production audit script
cat > full-audit.sh << 'EOF'
#!/bin/bash
set -e

echo "🔍 Starting comprehensive audit..."

# 1. Compile and check dependencies
echo "Step 1: Compilation"
forge build

# 2. AI analysis
echo "Step 2: AI audit (Claude)"
python audit.py

# 3. Static analysis
echo "Step 3: Slither"
slither . --exclude-dependencies --json slither-report.json

# 4. Test coverage
echo "Step 4: Test coverage"
forge coverage --report lcov

# 5. Gas optimization check
echo "Step 5: Gas report"
forge test --gas-report

# 6. Generate summary
cat > AUDIT_SUMMARY.md << 'SUMMARY'
# Audit Results - $(date)

## Critical Issues
$(grep -A 5 "CRITICAL" audit-report.md || echo "None found")

## High Severity
$(grep -A 5 "HIGH" audit-report.md || echo "None found")

## Coverage
$(forge coverage --report summary)

## Next Steps
- [ ] Fix critical issues
- [ ] Re-run tests
- [ ] Schedule professional audit
SUMMARY

echo "✅ Audit complete. Check AUDIT_SUMMARY.md"
EOF

chmod +x full-audit.sh
./full-audit.sh

Tools Comparison (2026)

ToolBest ForLimitationsCost
Claude Sonnet 4Logic flaws, explaining exploitsNeeds specific prompts$15/M tokens
GPT-4Pattern matching, known CVEsLess detailed explanations$30/M tokens
SlitherStandard vulnerabilitiesMany false positivesFree
MythrilBytecode-level issuesSlow on large contractsFree
CertoraFormal verificationRequires spec writingEnterprise

Recommended stack:

  1. AI for initial triage (Claude Sonnet 4)
  2. Slither for validation
  3. Manual review of AI + Slither overlap
  4. Professional firm for mainnet

Common Vulnerabilities AI Catches Well

1. Reentrancy

// AI detects: external call before state update
(bool success,) = recipient.call{value: amount}("");
balance -= amount; // ❌ Too late

2. Unchecked Return Values

// AI detects: ignored return value
token.transfer(recipient, amount); // ❌ Should check success

3. Access Control

// AI detects: missing modifier
function withdraw() public { // ❌ Anyone can call
    // Should be onlyOwner
}

4. Integer Overflow (Solidity <0.8.0)

// AI detects: unchecked arithmetic
uint256 total = balance + amount; // ❌ Can overflow

5. Front-Running

// AI detects: MEV vulnerability
function buyTokens() public payable {
    uint256 price = getCurrentPrice(); // ❌ Sandwich attack risk
    // Price can change before tx mines
}

Pro Tips

Prompt engineering for better results:

# ❌ Vague prompt
"Check this contract for security issues"

# ✅ Specific prompt
"Analyze for reentrancy in functions with external calls. 
For each finding, provide:
1. Attack scenario with example addresses
2. Profit calculation for attacker
3. Solidity 0.8+ compatible fix"

Handling false positives:

// AI may flag this as reentrancy
function safeWithdraw() public nonReentrant {
    // OpenZeppelin guard makes this safe
    (bool success,) = msg.sender.call{value: balance}("");
}

// Tell AI in comments:
// @audit This is safe - nonReentrant modifier prevents reentrancy

Version-specific analysis:

# Tell AI your Solidity version
"This contract uses Solidity 0.8.20. 
Ignore overflow checks (built-in since 0.8.0).
Focus on reentrancy and access control."

Tested with Claude Sonnet 4, Solidity 0.8.20, Foundry, Slither 0.10.0 Sample contracts available at: github.com/example/ai-audit-examples