A structured smart contract security audit workflow based on EEA EthTrust Security Levels V3 specification.
text
1. Project Preparation → 2. Automated Scanning → 3. Manual Review → 4. Testing & Verification → 5. Report Generation
Suitable for emergency situations or preliminary assessment:
text
1. Access Control Check (5 minutes)
- Owner permissions
- Sensitive function modifiers
2. Reentrancy Risk Check (5 minutes)
- External call positions
- State update order
3. Token Security Check (10 minutes)
- SafeERC20 usage
- Return value checks
4. Critical Vulnerability Scan (10 minutes)
- Integer overflow
- Signature verification
- Permission bypass
Capability DimensionAI AuditProfessional AuditGapBasic Vulnerabilities90%100%-10%Business Logic75%95%-20%Math Boundaries50%85%-35%Complex Interactions60%90%-30%
AI Advantages: Fast coverage, pattern matching, broad knowledge AI Disadvantages: Missing toolchain, limited depth analysis, boundary conditions
text
□ Number of logic contracts and their functions
□ Whether proxy contracts are included (upgradeability)
□ External dependencies (oracles, cross-chain bridges, etc.)
□ Deployment network (mainnet/L2/testnet)
LevelApplicable ScenariosCore Requirements[S] BasicSimple token contracts, basic DeFiNo known high-risk vulnerabilities, basic protection[M] IntermediateComplex DeFi, NFT markets, DAOsExternal call security, access control, oracle verification[Q] AdvancedCross-chain bridges, lending protocols, treasury managementBusiness logic verification, MEV protection, complete documentation
pragma solidity 0.8.20)Slither (Trail of Bits)
bash
# Installation
pip install slither-analyzer
# Basic scan
slither . --exclude-dependencies
# Output JSON format
slither . --exclude-dependencies --json output.json
# Specific detectors
slither . --detect reentrancy-eth,uninitialized-state
Aderyn (Rust-based, fast)
bash
# Installation
cargo install aderyn
# Scan
aderyn .
# Output report
aderyn . -o report.md
Tool DetectionEEA RequirementSecurity Leveltx.origin usage[S] No tx.originSselfdestruct[S] No selfdestruct()SCREATE2[S] No CREATE2Sassembly blocks[S] No assembly {}SReentrancy detection[M] External CallsMUninitialized variables[S] Initialize StateSUnchecked return values[M] Check Return ValuesM
bash
# Check for known compiler bugs
slither . --check-compiler-bugs
Refer to EEA § 3.9 Source code, pragma, and compilers for compiler-related security requirements.
solidity
// Check: Does transaction hash include chainId?
// Correct example:
keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR, // Includes chainId
hashStruct
))
// Dangerous: Without chainId allows cross-chain replay
CREATE2 usage justification, whether necessaryselfdestruct calls, confirm legitimate reasondelegatecall target address controllabilitysolidity
// Dangerous: Using tx.origin for authorization
require(tx.origin == owner); // Phishing attack risk
// Correct: Use msg.sender
require(msg.sender == owner);
solidity
// Dangerous: Hash collision with consecutive variable-length parameters
keccak256(abi.encodePacked(str1, str2)); // str1="ab", str2="c" == str1="a", str2="bc"
// Safe: Use encode or fixed length
keccak256(abi.encode(str1, str2));
assembly blockssolidity
// CEI Pattern Check (Checks-Effects-Interactions)
function withdraw() external {
// 1. Checks
require(balances[msg.sender] > 0, "No balance");
// 2. Effects (update state first)
balances[msg.sender] = 0;
// 3. Interactions (external calls last)
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
// Read-only reentrancy check: Are view functions called externally before state updates?
solidity
// Check: Is there price deviation detection?
uint256 price = oracle.getPrice();
require(price > 0 && price < MAX_PRICE, "Invalid price");
// Check: Is there timestamp validation?
require(block.timestamp - oracle.lastUpdate() < HEARTBEAT, "Stale data");
solidity
// Dangerous: Unprotected initialization function
function initialize() external {
owner = msg.sender; // Anyone can call!
}
// Safe: Use OpenZeppelin Initializable
function initialize() external initializer {
owner = msg.sender;
}
solidity
// Solidity 0.8+ checks overflow by default
// But need to check unchecked blocks:
unchecked {
// Overflow here will not be detected!
uint256 result = a + b; // Dangerous
}
// Special case: Loop counters can safely use unchecked
for (uint256 i; i < n; ) {
// ...
unchecked { i++; }
}
solidity
// AMM sandwich attack example
// User transaction: A -> B
// Attacker: Buy B before user transaction, sell B after
// Protection: Use TWAP, slippage protection
solidity
// Check items:
// 1. Is the proxy contract implementation correct?
// 2. Is the initialization function protected against reentry?
// 3. Are upgrade permissions reasonable?
// 4. Is there storage layout conflict?
// Dangerous: Storage layout conflict
// V1: uint256 a; uint256 b;
// V2: uint256 a; address c; uint256 b; // c overwrites b's slot!
Governance contract vulnerabilities are often more subtle but have greater impact, requiring specialized review.
solidity
// Dangerous example: State sync uses wrong account balance
function notifyFor(address account) external {
_notifyFor(account, balanceOf(msg.sender)); // Wrong!
// Should be balanceOf(account)
}
// Check points:
// 1. Is governance module synchronized with main contract state
// 2. Does notify function use correct account address
// 3. Is stake increase/decrease order correct
solidity
// High-risk pattern: Similar code blocks
function _beforeTokenTransfer(address from, address to, uint256 amount) {
uint256 balanceFrom = (from != address(0)) ? balanceOf(from) : 0;
uint256 balanceTo = (from != address(0)) ? balanceOf(to) : 0; // Copy-paste error!
// Should be: (to != address(0)) ? balanceOf(to) : 0
}
// Detection method:
// 1. Find code blocks with > 80% similarity
// 2. Compare each difference character by character
// 3. Verify each difference is intentional
Must Complete:
text
Example dependency graph:
┌─────────────────┐
│ GovernanceMothership │
│ (Master) │
└────────┬────────┘
│ notify
▼
┌─────────────────┐ ┌─────────────────┐
│ FactoryGovernance │ │ RewardsGovernance │
│ (Slave 1) │ │ (Slave 2) │
└─────────────────┘ └─────────────────┘
Check Points:
solidity
// List all onlyOwner/onlyAdmin functions
// Analyze impact scope of each function
// Dangerous pattern: Admin can lock user funds
function emergencyPause() external onlyOwner {
paused = true; // Users cannot withdraw funds!
}
// Dangerous pattern: Parameter modification without timelock
function setFeeReceiver(address newReceiver) external onlyOwner {
feeReceiver = newReceiver; // Can immediately set malicious contract
}
solidity
// Check point: State validation after flash loan callback
// Dangerous example: Only check balance, not mapping
function flashLoan(uint256 amount) external {
uint256 balanceBefore = address(this).balance;
IFlashLoanReceiver(msg.sender).execute{value: amount}();
// ⚠️ Only check balance, not balances mapping!
if (address(this).balance < balanceBefore) revert RepayFailed();
}
// Correct approach: Check all relevant states
function flashLoan(uint256 amount) external {
uint256 balanceBefore = address(this).balance;
uint256 depositsBefore = totalDeposits; // Record mapping state
IFlashLoanReceiver(msg.sender).execute{value: amount}();
require(address(this).balance >= balanceBefore, "Balance not restored");
require(totalDeposits == depositsBefore, "Deposits changed"); // Verify mapping
}
solidity
// Dangerous: Using current reserves as price
function _computePrice() private view returns (uint256) {
return uniswapPair.balance * 1e18 / token.balanceOf(uniswapPair);
// ⚠️ Reserves can be manipulated by large trades!
}
// Safe: Use TWAP or Chainlink
function _computePrice() private view returns (uint256) {
(uint256 price0Cumulative, uint256 price1Cumulative,) =
UniswapV2OracleLibrary.currentCumulativePrices(pair);
// Use time-weighted average price
}
// Safe Chainlink usage
function getPrice() public view returns (uint256) {
(, int256 price,, uint256 timestamp,) = oracle.latestRoundData();
require(price > 0, "Invalid price");
require(block.timestamp - timestamp < HEARTBEAT, "Stale data");
return uint256(price);
}
solidity
// Dangerous: Only check current voting power
function queueAction(...) external returns (uint256) {
if (!_hasEnoughVotes(msg.sender)) revert NotEnoughVotes();
// ⚠️ Attacker can temporarily gain voting power via flash loan!
}
// Safe: Require voting power holding time
function queueAction(...) external returns (uint256) {
if (!_hasHeldVotesFor(msg.sender, VOTING_DELAY)) revert NotEnoughVotes();
// Check voting power for past N blocks
}
function _hasHeldVotesFor(address who, uint256 blocks) private view returns (bool) {
for (uint256 i = 0; i < blocks; i++) {
if (getVotesAtBlock(who, block.number - i) <= threshold) return false;
}
return true;
}
See references/secureum-knowledge.md for details
#Check ItemDescriptionReference1pragma version lockedpragma solidity 0.8.20; not ^0.8.0#22Access control completenessAll sensitive functions have permission modifiers#4-83delegatecall target verificationTarget address must be trusted#124Reentrancy protectionCEI pattern or ReentrancyGuard#13-155Random number safetyDon't use block.timestamp/blockhash as random source#176Integer overflowCheck unchecked blocks#197Multiply before divideAvoid precision loss#208ERC20 approve raceapprove(0) then approve(new)#22, #1059Signature malleabilityVerify signature format before ecrecover#2310ERC20 return valuesUse SafeERC20#2411Unexpected ETHselfdestruct can force send ETH#2612tx.origin authorizationProhibit for authorization checks#3013mapping deletionDeleting struct doesn't clear internal mapping#3214Low-level call return valuesCheck call/send/delegatecall return values#3715External calls in loopsMay cause DoS#4316Unbounded loopsMay cause out of gas#4417Event emissionEmit events for critical state changes#4518Zero address validationCheck address parameters#4919require vs assertrequire for conditions, assert for invariants#5220Deprecated keywordsAvoid throw/callcode/suicide#5321Function visibilityMust be explicitly declared#5422Inheritance orderAffects initialization order#5523Hash collisionabi.encodePacked with multiple variable parameters#6024Assembly codeNeeds detailed comments and review#6325Uninitialized variablesEspecially storage pointers#67-6826Proxy initialization protectioninitializer modifier#95-9627Proxy storage layoutMaintain consistency during upgrades#9928ERC777 hooksMay trigger reentrancy#10629Deflationary/inflationary tokensTransfer amounts may not match#107-10830Two-step permission changeCritical operations need timelock or two-step verification#162-163
text
1. Read specification docs → 2. Run static analyzers → 3. Manual code review
4. Run deep tools → 5. Discuss with team → 6. Write report
MethodStarting PointAccess ControlStart with permission checksAsset FlowStart with asset flowControl FlowEvaluate control flowData FlowEvaluate data flowConstraintsInfer constraint conditionsDependenciesUnderstand dependenciesAssumptionsEvaluate assumptionsChecklistsUse checklists
bash
# Installation
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Initialize
forge init my-test
# Run tests
forge test -vvv
# Fuzz testing
forge test --fuzz-runs 10000
# Gas report
forge test --gas-report
solidity
// test/ReentrancyPoC.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/VulnerableContract.sol";
contract ReentrancyPoC is Test {
VulnerableContract target;
Attacker attacker;
function setUp() public {
target = new VulnerableContract();
attacker = new Attacker(address(target));
vm.deal(address(target), 10 ether);
vm.deal(address(attacker), 1 ether);
}
function test_Reentrancy() public {
uint256 initialBalance = address(attacker).balance;
// Execute attack
attacker.attack{value: 1 ether}();
// Verify: Attacker balance should be greater than initial
assertGt(address(attacker).balance, initialBalance);
console.log("Stolen:", address(attacker).balance - initialBalance);
}
}
contract Attacker {
VulnerableContract target;
constructor(address _target) {
target = VulnerableContract(_target);
}
function attack() external payable {
target.deposit{value: msg.value}();
target.withdraw();
}
receive() external payable {
if (address(target).balance > 0) {
target.withdraw();
}
}
}
solidity
// test/FuzzTest.t.sol
function testFuzz_Transfer(address to, uint256 amount) public {
vm.assume(to != address(0));
vm.assume(to != address(this));
vm.assume(amount <= token.balanceOf(address(this)));
uint256 balanceBefore = token.balanceOf(to);
token.transfer(to, amount);
uint256 balanceAfter = token.balanceOf(to);
assertEq(balanceAfter - balanceBefore, amount);
}
Vulnerability TypeTest MethodCoverage TargetReentrancy attacksUnit tests + PoCAll external call pointsInteger overflowFuzz testingunchecked blocksAccess controlUnit testsAll permission functionsBusiness logicIntegration testsCore functionality paths
markdown
# [Project Name] Smart Contract Security Audit Report
## 1. Summary
- **Audit Period**: YYYY-MM-DD to YYYY-MM-DD
- **Audit Scope**: Contract list and versions
- **Security Level Target**: [S]/[M]/[Q]
- **Total Findings**: High X / Medium Y / Low Z / Informational W
## 2. Audit Scope
| File | Lines | Description |
|------|-------|-------------|
| ContractA.sol | 123 | Core logic |
| ContractB.sol | 456 | Proxy contract |
## 3. Findings Details
### [High] R-01: Reentrancy Vulnerability
**Location**: `Vault.sol#withdraw()` line 42
**EEA Spec**: Violates [M] External Calls
**Description**: External call before state update, attacker can reenter to drain funds
**Impact**: Funds can be completely stolen
**Reproduction Steps**:
1. Deploy attacker contract
2. Call deposit to deposit 1 ETH
3. Call withdraw to trigger reentrancy
4. Verify contract balance is zero
**Recommendation**:
```solidity
// Use ReentrancyGuard or CEI pattern
function withdraw() external nonReentrant {
// ...
}
RequirementStatusNotes[S] No tx.origin✅ Pass-[S] No selfdestruct✅ Pass-[M] External Calls❌ FailR-01[Q] Documentation⚠️ PartialMissing architecture diagram
text
## References
### Detailed Reference Documents
- **EEA Specification Details**: See [references/eea-requirements.md](references/eea-requirements.md)
- **Vulnerability Checklist**: See [references/vulnerability-checklist.md](references/vulnerability-checklist.md)
- **Testing Guide**: See [references/testing-guide.md](references/testing-guide.md)
- **SecureUM Knowledge Base**: See [references/secureum-knowledge.md](references/secureum-knowledge.md) - 200+ audit knowledge points
### External Resources
- EEA EthTrust V3 Specification: https://entethalliance.org/specs/ethtrust-sl/v3/
- Secureum Knowledge Graph: https://github.com/x676f64/secureum-mind_map
- OpenZeppelin Contracts: https://docs.openzeppelin.com/contracts
- EIP Standards List: https://eips.ethereum.org/all
- Mastering Ethereum: https://masteringethereum.xyz/
### Common Tools
| Tool | Purpose | Link |
|------|---------|------|
| Slither | Static analysis | https://github.com/crytic/slither |
| Aderyn | Fast scanning | https://github.com/Cyfrin/aderyn |
| Foundry | Test framework | https://github.com/foundry-rs/foundry |
| Echidna | Fuzz testing | https://github.com/crytic/echidna |
| Mythril | Symbolic execution | https://github.com/ConsenSys/mythril |
## Usage Example
User: Help me audit this ERC20 contract for security
AI: I will perform a basic audit following EEA EthTrust specification:
text
## Audit Capability Assessment Framework
### Audit Quality Self-Assessment
After completing an audit, use this framework for self-evaluation:
| Dimension | Check Item | Assessment Method |
|-----------|------------|-------------------|
| Coverage | Did you review all core contracts | Contract checklist |
| Depth | Did you discover complex logic vulnerabilities | PoC verification |
| Tools | Did you use automated tools | Slither/Aderyn reports |
| Comparison | Compare with professional reports | Gap analysis |
### Capability Level Classification
| Level | Standard | Typical Performance |
|-------|----------|---------------------|
| Junior | Can find basic vulnerabilities | Reentrancy, permission issues, overflow |
| Intermediate | Can find business logic issues | Price manipulation, liquidation issues |
| Senior | Can find complex interaction vulnerabilities | Cross-chain, composability attacks |
| Expert | Can design security architecture | Formal verification, zero-knowledge proofs |
### Audit Time Reference
| Contract Size | Junior | Intermediate | Senior |
|---------------|--------|--------------|--------|
| <500 lines | 2 hours | 1 hour | 30 minutes |
| 500-2000 lines | 8 hours | 4 hours | 2 hours |
| 2000-10000 lines | 40 hours | 20 hours | 10 hours |
| >10000 lines | 2 weeks+ | 1 week+ | 3 days+ |
### Common Missed Checks
After completing an audit, check if you missed:
- [ ] Callback function security
- [ ] Multi-signature/timelock configuration
- [ ] Special token compatibility (rebasing, fee-on-transfer)
- [ ] Cross-chain message verification
- [ ] Price precision issues
- [ ] Gas limit boundary conditions
- [ ] Upgrade pattern security
- [ ] Signature verification security
### 🎯 Professional Audit Comparison Template
After completing an audit, compare using this format:
```markdown
## My Findings vs Professional Audit
### Matched Items
| My Finding | Professional Audit Finding | Match Level |
|------------|---------------------------|-------------|
| Reentrancy risk | ✅ Usually found | High |
| Permission issues | ✅ Usually found | High |
### Missed Items
| Professional Finding | Why I Missed It |
|---------------------|-----------------|
| Math boundaries | Need fuzz testing |
| Interaction vulnerabilities | Need symbolic execution |
### Capability Score
- This round score: X/100
- Cumulative average: Y/100
StageTargetMethodJunior→Intermediate78→85 pointsMore practice cases, learn vulnerability patternsIntermediate→Senior85→92 pointsUse toolchain, deep protocol researchSenior→Expert92→98 pointsFormal verification, innovative attack vectors
Problem: AI cannot directly run Slither/Foundry
Solution: Request user to run tools, AI analyzes results
text
Please provide tool scan results for audit:
# Slither quick scan
slither . --exclude-dependencies --json slither.json
# Or Aderyn scan
aderyn . -o report.md
Provide the output to me, and I will combine tool findings with deep analysis.
Tool Output Mapping:
Slither DetectorAI Analysis Focusreentrancy-ethVerify reentrancy protectionuninitialized-stateCheck initializationarbitrary-sendVerify sending logiccontrolled-delegatecallVerify target address
Problem: Limited audit time
Solution: Focus on high-risk modules
35-minute Allocation:
text
Access Control (5 minutes): owner/governor/permission modifiers
Reentrancy Check (5 minutes): external calls + state update order
Token Security (10 minutes): SafeERC20/return value checks
Critical Vulnerabilities (10 minutes): liquidation/price/permission bypass
Report Output (5 minutes): formatted output
High-Risk Function Priority:
Problem: Unfamiliar with new protocol features
Solution: Protocol type knowledge base
Protocol TypeCore Check PointsAMMPrice calculation, liquidity, slippageLendingLiquidation factors, interest rates, oraclesCross-chainSignature verification, message replayAggregatorInteraction order, composability risksNFTTransfers, royalties, authorization
See: references/toolchain-guide.md for details