blockchain-auditor
Blockchain Security Auditor
Systematically audit smart contracts to identify exploitable vulnerabilities that allow an unprivileged account to extract funds or gain unauthorized access.
Quick Start
# For verified contracts (Etherscan source available)
cast etherscan-source <address> --chain mainnet
# For unverified contracts (bytecode only)
cast code <address> --rpc-url $ETH_RPC_URL
cast disassemble <bytecode>
# Fork testing
forge test --fork-url $ETH_RPC_URL -vvv
# Static analysis
slither . --checklist
Audit Methodology
Phase 1: Reconnaissance
-
Gather contract information:
# Check balance cast balance <address> --rpc-url $ETH_RPC_URL # Get bytecode cast code <address> --rpc-url $ETH_RPC_URL # Check if verified on Etherscan curl "https://api.etherscan.io/api?module=contract&action=getsourcecode&address=<address>&apikey=$ETHERSCAN_API_KEY" # Check for proxy implementation cast storage <address> 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url $ETH_RPC_URL -
Identify contract type:
- Multi-sig wallet (addOwner, execute, confirmTransaction)
- Token contract (transfer, approve, balanceOf)
- DeFi protocol (deposit, withdraw, swap, liquidate)
- Lending/borrowing (Compound/Aave-style)
- AMM/DEX (Uniswap v2/v3-style with liquidity pools)
- Proxy pattern (EIP-1967, UUPS, Transparent, Beacon)
- Vault/yield aggregator (ERC-4626)
- Cross-chain bridge (lock/mint, burn/release)
- NFT contract (ERC-721, ERC-1155)
Phase 2: Source Code Analysis (Verified Contracts)
-
Identify high-risk functions:
selfdestruct/suicide- can drain all ETHdelegatecall- can execute arbitrary codecallwith user-controlled data - arbitrary callstransfer/sendwithout checks - reentrancywithdraw/claim/redeem- fund extraction pointsinitialize/init- proxy initialization (can it be called twice?)permit/permitAll- off-chain approval bypassflash/flashLoan- flash loan entry points
-
Check access control patterns:
// Weak patterns to look for: require(tx.origin == owner); // tx.origin bypass require(msg.sender == owner); // Check if owner is compromised // Missing modifier on sensitive function function withdraw() public { // No onlyOwner! payable(msg.sender).transfer(address(this).balance); } // Proxy: unprotected initialize function initialize(address _owner) public { // Missing initializer modifier! owner = _owner; } -
Known vulnerability patterns:
- Reentrancy (state change after external call)
- Integer overflow/underflow (Solidity < 0.8.0)
- Unchecked return values
- Front-running susceptibility
- Flash loan attacks (price manipulation in single tx)
- Price oracle manipulation (spot vs TWAP)
- Permit/EIP-2612 signature replay
- ERC777 callback reentrancy
- Read-only reentrancy (view functions misused in logic)
- Donation attacks (token balance inflation)
- First depositor share inflation (ERC-4626 vaults)
Phase 3: DeFi-Specific Attack Vectors
For DeFi protocols, these vectors are highest-value and commonly exploitable:
-
Price Oracle Manipulation:
// Vulnerable: spot price used as oracle function getPrice() public view returns (uint256) { (uint112 reserve0, uint112 reserve1,) = IUniswapV2Pair(pool).getReserves(); return reserve1 * 1e18 / reserve0; // Manipulable in a single tx! } // Attack: flash loan → manipulate pool → call vulnerable function → repay- Check if protocol uses spot prices anywhere
- TWAP oracles are safe; Chainlink feeds are safe (within heartbeat)
- Look for
getReserves(),slot0(), direct AMM pool queries
-
Flash Loan Attack Surface:
- Can any state-changing function be called with borrowed funds?
- Check: borrow large amount → do something → repay in same tx
- Key question: does the protocol measure prices/balances before or after user deposits?
-
Reentrancy Variants:
// Cross-function reentrancy function withdraw() external { // State updated after transfer → reenter via deposit() IERC20(token).safeTransfer(msg.sender, amounts[msg.sender]); amounts[msg.sender] = 0; // Too late! } // Read-only reentrancy (in Curve, Balancer) // Attack: during callback, totalSupply() returns old value // Another protocol reads it via getVirtualPrice() during the callback -
ERC-4626 Vault Inflation Attack:
- First depositor can inflate share price by donating tokens
- Target: protocols that mint shares =
(deposit * totalShares) / totalAssets - If
totalShares = 0, first depositor getsdepositshares; then donate to inflate
-
Signature/Permit Vulnerabilities:
// EIP-2612 permit can be front-run // Front-runner takes the permit, uses it themselves before victim's tx // Safe if permit is used atomically in the same tx // Check: does permit use chainId? (cross-chain replay) // Check: does it use nonces? (replay protection) -
Governance/Timelock Attacks:
- Can governance propose and execute malicious upgrades?
- Is there a timelock? How long?
- Can flash loan voting power bypass quorum?
Phase 4: Bytecode Analysis (Unverified Contracts)
-
Disassemble bytecode:
cast disassemble <bytecode> > contract.asm -
Extract function selectors:
# Look for PUSH4 followed by 4 bytes grep -oE '63[0-9a-f]{8}' contract.asm | cut -c3-10 | sort -u -
Look up signatures:
curl "https://www.4byte.directory/api/v1/signatures/?hex_signature=0x<selector>" # Also try openchain.xyz/signature-database -
Identify dangerous opcodes:
Opcode Hex Risk SELFDESTRUCT ffCritical - destroys contract DELEGATECALL f4High - arbitrary code execution CALL f1Medium - external calls CALLCODE f2High - deprecated, dangerous CREATE2 f5Medium - deterministic deployment TLOAD/TSTORE 5c/5dNew in EIP-1153 - transient storage -
Analyze control flow:
- Find JUMPDEST locations for function entry points
- Trace CALLER/ORIGIN checks for access control
- Look for SLOAD/SSTORE patterns for state access
Phase 5: Vulnerability Ranking
Rate each finding by exploitation likelihood given current blockchain state:
| Rating | Criteria | Action |
|---|---|---|
| Critical | Directly exploitable now, high value | Immediate PoC |
| High | Exploitable with specific conditions met | Fork test |
| Medium | Requires unlikely conditions | Document |
| Low | Theoretical, conditions very unlikely | Note only |
Factors affecting likelihood:
- Current blockchain state (owner keys, time locks, balances)
- Required preconditions (deposits, approvals, block numbers)
- Gas costs vs potential gain
- MEV/frontrunning risks (can an attacker sandwich?)
- Flashbots private mempool availability
Phase 6: Fork Validation
-
Set up Foundry test:
// test/Exploit.t.sol pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "forge-std/interfaces/IERC20.sol"; interface IFlashLoanProvider { function flashLoan(uint256 amount) external; } contract ExploitTest is Test { address target = 0x<TARGET_ADDRESS>; address attacker; function setUp() public { // Fork at specific block for determinism vm.createSelectFork(vm.envString("ETH_RPC_URL"), <BLOCK_NUMBER>); attacker = makeAddr("attacker"); vm.deal(attacker, 1 ether); } function test_exploit() public { uint256 balanceBefore = attacker.balance; vm.prank(attacker); (bool success,) = target.call(abi.encodeWithSelector(0x<SELECTOR>)); uint256 balanceAfter = attacker.balance; // CRITICAL: Verify actual fund extraction assertGt(balanceAfter, balanceBefore, "Exploit failed - no funds extracted"); } // Flash loan exploit template function test_flashLoanExploit() public { uint256 targetBalanceBefore = IERC20(token).balanceOf(target); vm.prank(attacker); FlashLoanAttacker exploitContract = new FlashLoanAttacker(target); exploitContract.attack(); assertLt(IERC20(token).balanceOf(target), targetBalanceBefore, "No drain"); assertGt(IERC20(token).balanceOf(attacker), 0, "No profit"); } } -
Run on fork:
forge test --fork-url $ETH_RPC_URL -vvvv --match-test "test_exploit" -
Verify fund extraction (not just call success):
- Check attacker balance increased
- Verify target balance decreased
- Confirm contract state changed as expected
- Call success does NOT mean exploit success
Phase 7: Report Generation
For confirmed vulnerabilities, create a report:
# Vulnerability Report: [Contract Address]
## Summary
- **Severity**: Critical/High/Medium/Low
- **Type**: [Reentrancy/Access Control/Oracle Manipulation/etc.]
- **Impact**: [Amount at risk, what attacker gains]
- **Exploitable**: Yes/No (with current blockchain state)
- **Block confirmed**: [Block number of fork test]
## Vulnerable Function
\`\`\`solidity
function vulnerableFunction() public {
// Vulnerable code
}
\`\`\`
## Attack Vector
1. Attacker calls function X with parameter Y
2. Contract fails to check Z
3. Funds transferred to attacker
## Proof of Concept
\`\`\`solidity
// Foundry test that demonstrates the exploit
function test_exploit() public {
// Setup and exploit code
}
\`\`\`
## Execution Script (if confirmed)
\`\`\`bash
cast send <target> "vulnerableFunction()" --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY
\`\`\`
## Remediation
- Add access control modifier
- Implement checks-effects-interactions pattern
- Use SafeMath for arithmetic (or upgrade to Solidity >= 0.8.0)
- Replace spot price with TWAP oracle
Common Vulnerability Checklist
Access Control
- All sensitive functions have proper modifiers
- Owner/admin addresses are not compromised
- Multi-sig requires sufficient confirmations
- Time locks are enforced
- No tx.origin authentication
- Proxy initializer cannot be called twice
- UUPS upgrade function is access-controlled
- Governance quorum cannot be bypassed with flash loans
Reentrancy
- State changes before external calls (CEI pattern)
- ReentrancyGuard used on fund transfers
- No callbacks to untrusted contracts
- ERC-777 tokensReceived hook considered
- Cross-function reentrancy checked
- Read-only reentrancy checked (getVirtualPrice, exchange rate)
Arithmetic (Solidity < 0.8.0)
- SafeMath used for all operations
- No unchecked blocks with user input
- Proper bounds checking
- Check for 0.5.x - 0.6.x overflow vulnerabilities
Oracle / Price Manipulation
- No spot price oracles (flash-loan manipulable)
- TWAP used where applicable
- Chainlink heartbeat freshness checked
- Multi-oracle aggregation for critical paths
- Pool balances not used as price source
Flash Loans
- State cannot be manipulated then read in same tx
- No price/ratio checks after untrusted external calls
- Reentrancy guard on all flash-loan-callable functions
DeFi-Specific
- ERC-4626 first-depositor share inflation protected (virtual shares/assets)
- Permit/EIP-2612 replay protection (nonce, chainId)
- Donation attack protection for balance-based accounting
- MEV sandwich protection where relevant
- Cross-chain bridge: message replay protection
External Calls
- Return values checked
- Gas limits set appropriately
- Fallback/receive functions handled
Solidity Version-Specific Issues
| Version | Issue | Check |
|---|---|---|
| < 0.8.0 | Integer overflow/underflow | SafeMath usage |
| < 0.6.0 | Constructor name confusion | constructor() keyword |
| < 0.5.0 | Uninitialized storage pointers | Variable declarations |
| Any | tx.origin authentication | Access control patterns |
| Any | Proxy storage collision | EIP-1967 slots used |
False Positive Indicators
Be aware of patterns that look exploitable but aren't:
- Multi-sig pending transactions:
kill()succeeds but requires N-of-M confirmations - User-specific balances:
withdraw()only returns caller's deposited amount - Time-locked releases: Funds go to hardcoded address, not caller
- Proxy patterns: Implementation has checks even if proxy doesn't
- Call success without transfer: Function completes but no ETH moves
- Flash loan with immediate repayment check: Can't exploit if balance is verified at end
- Pausable contracts: Admin can pause, but that's by design
ALWAYS verify actual fund movement on fork before concluding exploitability.
Tools Reference
| Tool | Purpose | Command |
|---|---|---|
| cast | RPC calls, disassembly | cast code/call/send/disassemble |
| forge | Fork testing | forge test --fork-url |
| anvil | Local fork node | anvil --fork-url $RPC |
| slither | Static analysis | slither . --checklist |
| 4byte.directory | Selector lookup | API or web |
| openchain.xyz | Selector lookup | API or web |
| Etherscan | Source code, ABI | API or web |
| Mythril | Symbolic execution | myth analyze |
| Tenderly | Transaction simulation | Web UI |
| Dedaub | Decompiler for bytecode | dedaub.com |
Environment Setup
Required environment variables:
export ETH_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/<KEY>"
export ETHERSCAN_API_KEY="<KEY>"
Required tools:
# Foundry (forge, cast, anvil)
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Slither
pip3 install slither-analyzer
# Node.js (for Hardhat if needed)
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
Example Workflow
# 1. Check contract value and code
cast balance 0x<address> --rpc-url $ETH_RPC_URL
cast code 0x<address> --rpc-url $ETH_RPC_URL > bytecode.hex
# 2. Check for proxy (EIP-1967 slot)
cast storage 0x<address> 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url $ETH_RPC_URL
# 3. Disassemble if unverified
cast disassemble $(cat bytecode.hex) > contract.asm
# 4. Extract and lookup selectors
grep -oE '63[0-9a-f]{8}' contract.asm | cut -c3-10 | sort -u | while read sel; do
sig=$(curl -s "https://www.4byte.directory/api/v1/signatures/?hex_signature=0x$sel" | jq -r '.results[0].text_signature // "unknown"')
echo "0x$sel: $sig"
done
# 5. Run slither on source (if available)
slither . --checklist 2>&1 | head -100
# 6. Create and run fork test
forge test --fork-url $ETH_RPC_URL -vvvv
# 7. Verify fund extraction (not just call success!)
# 8. Generate report if confirmed exploitable
Database Integration
When auditing multiple contracts, track findings in SQLite:
CREATE TABLE contracts (
address TEXT PRIMARY KEY,
balance_usd REAL,
is_verified INTEGER,
exploitable INTEGER DEFAULT 0,
attack_type TEXT,
notes TEXT
);
-- Update after analysis
UPDATE contracts SET
exploitable = 0,
notes = 'Multi-sig wallet. kill() requires confirmations. NOT exploitable.'
WHERE address = '0x...';
Security & Legal Notes
- Only test on forks, never mainnet without explicit authorization
- Document all findings, including false positives
- Consider responsible disclosure for live vulnerabilities
- Be aware of legal implications of exploit execution
- This skill is for authorized security research only
- Immunefi, Code4rena, Sherlock — report via official bug bounty channels
More from ckorhonen/claude-skills
video-editor
Expert guidance for video editing with ffmpeg, encoding best practices, and quality optimization. Use when working with video files, transcoding, remuxing, encoding settings, color spaces, or troubleshooting video quality issues.
63tui-designer
Design and implement retro/cyberpunk/hacker-style terminal UIs. Covers React (Tuimorphic), SwiftUI (Metal shaders), and CSS approaches. Use when creating terminal aesthetics, CRT effects, neon glow, scanlines, phosphor green displays, or retro-futuristic interfaces.
35practical-typography
Professional typography guidance based on Matthew Butterick's Practical Typography. Use when evaluating, critiquing, or improving document formatting, text layout, font choices, punctuation, spacing, or any typography-related decisions for print or web content.
34app-marketing-copy
Write marketing copy and App Store / Google Play listings (ASO keywords, titles, subtitles, short+long descriptions, feature bullets, release notes), plus screenshot caption sets and text-to-image prompt templates for generating store screenshot backgrounds/promo visuals. Use when asked to: write/refresh app marketing copy, craft app store metadata, brainstorm taglines/value props, produce ad/landing/email copy, or generate prompts for screenshot/creative generation.
33markdown-fetch
Fetch and extract web content as clean Markdown when provided with URLs. Use this skill whenever a user provides a URL (http/https link) that needs to be read, analyzed, summarized, or extracted. Converts web pages to Markdown with 80% fewer tokens than raw HTML. Handles all content types including JS-heavy sites, documentation, articles, and blog posts. Supports three conversion methods (auto, AI, browser rendering). Always use this instead of web_fetch when working with URLs - it's more efficient and provides cleaner output.
26llm-advisor
Consult other LLMs (GPT-4.1, o4-mini, Gemini 2.5 Pro, Claude Opus) for second opinions on complex bugs, hard problems, planning, and architecture decisions. Use proactively when stuck for 15+ minutes or facing complex debugging. Use when user says 'ask Gemini/GPT/Claude about X' or 'get a second opinion'.
22