Audit Guide
The Complete DeFi Security
Audit Checklist for 2026
80+ security checks across 12 categories. The practical checklist that protocol teams use before mainnet deployment — from code-level patterns to economic attack modeling.
Security is not a one-time gate. It's a continuous process that starts at the first line of code and continues long after mainnet deployment. This checklist distills the lessons from hundreds of DeFi exploits into a practical, actionable format that protocol teams can use at every stage of development.
We've organized the checklist into three phases: development (checks during coding), pre-deployment (checks before going live), and post-deployment (ongoing monitoring). Most items should be verified during development, but some only become relevant at deployment time.
How to use this checklist: Work through each category systematically. For each item, verify it applies to your protocol and mark it as checked, not applicable, or needs-fix. Items marked as needs-fix should be resolved and re-verified before deployment. Use our free scanner to automatically check many of these items.
All external calls follow the Checks-Effects-Interactions pattern — state updates happen before any external calls
Functions that transfer ETH or tokens use ReentrancyGuard (or equivalent nonReentrant modifier)
Cross-function reentrancy is considered — no function reads state that could be stale during reentrancy from another function
Read-only reentrancy is considered — view functions called by external protocols return correct values during reentrancy
State is consistent before and after every external call — no partial state updates visible to re-entrant callers
Callback hooks (ERC-721 onERC721Received, ERC-1155 hooks, ERC-777 hooks) are handled safely with reentrancy protection
Multi-contract systems consider reentrancy across contract boundaries, not just within a single contract
Every external and public function has been reviewed for correct access control (onlyOwner, onlyRole, etc.)
Critical functions (mint, burn, pause, upgrade, withdraw, setFee) are restricted to appropriate roles
tx.origin is never used for authorization — only msg.sender
Multi-sig or timelock is required for admin operations that affect user funds
Role-based access control uses least privilege — each role has only the permissions it needs
Ownership transfer uses a two-step process (propose + accept) to prevent accidental transfers
Initialize functions can only be called once and are protected on implementation contracts
No functions have unprotected selfdestruct or delegatecall to arbitrary addresses
All unchecked blocks have been individually verified to be safe from overflow/underflow
Division before multiplication patterns have been eliminated — multiply first, divide last
Division by zero is impossible in all arithmetic operations (denominators validated or guaranteed non-zero)
Token decimal differences are handled correctly when comparing or converting between tokens with different decimals
Rounding direction is explicitly chosen and favors the protocol (round down for user withdrawals, round up for user deposits)
Calculations involving large numbers have been tested at boundary values (type(uint256).max, 0, 1, etc.)
Casting between types (uint256 to uint128, int256 to uint256) is safe and validated
Price feeds use TWAP or Chainlink — never single-block spot prices from AMM pools
Oracle staleness is checked — stale prices (e.g., Chainlink heartbeat exceeded) trigger a revert or fallback
Oracle manipulation resistance has been evaluated — cost to manipulate the oracle exceeds potential profit
Multiple oracle sources are used for critical price data, with deviation checks between them
L2/sidechain sequencer uptime is verified when using Chainlink on L2s (sequencer uptime feed)
Price bounds are enforced — prices outside reasonable ranges are rejected
The protocol gracefully handles oracle failure rather than bricking all operations
SafeERC20 is used for all token transfers (handles non-standard return values)
Fee-on-transfer tokens are handled correctly — actual received amount is checked, not assumed
Rebasing tokens are either explicitly supported or explicitly documented as unsupported
ERC-777 callback reentrancy is protected against (tokensReceived hook)
The protocol handles tokens with different decimals (6, 8, 18) correctly
Token approval race conditions are handled (use increaseAllowance/decreaseAllowance or approve-to-zero first)
The protocol documents which token types are supported and which are not
The protocol's security model does not assume attackers need capital (flash loans provide unlimited single-tx capital)
First depositor attack is prevented (vault share price cannot be manipulated by the first depositor with dust amounts)
Donation attacks are considered — direct token transfers to the contract cannot manipulate internal accounting
Pool ratio manipulation within a single transaction is accounted for
Liquidation mechanisms are resistant to price manipulation attacks
Fee extraction paths have been reviewed — no way to avoid fees through clever transaction ordering
The protocol's invariants (total supply == sum of balances, etc.) are documented and tested
All swaps include slippage parameters (minAmountOut) that users can set
Transaction deadlines are enforced to prevent stale transactions from executing at unfavorable prices
Sensitive operations use commit-reveal schemes where appropriate (auctions, governance votes)
The protocol considers sandwich attack resistance for large operations
Block.timestamp is not used for critical randomness (miners can manipulate within limits)
Storage layout between proxy and implementation is verified — no slot collisions
Implementation contracts have initializers disabled (cannot be initialized directly)
Upgrade function is protected with timelock and multi-sig
Storage layout tests verify that new implementation is compatible with existing storage
Standard proxy patterns are used (ERC-1967 storage slots, OpenZeppelin TransparentProxy or UUPS)
Gap variables are used in base contracts to allow future storage additions
If using UUPS, the _authorizeUpgrade function has proper access control
No unbounded loops over arrays that can grow with user input
Pull-over-push pattern is used for distributions (users withdraw rather than contract pushes)
External call failures do not block the entire function (handle failures gracefully)
Gas costs for critical user operations are reasonable and predictable
Functions that iterate over data structures have upper bounds on iteration count
Batch operations have limits to prevent single-transaction gas exhaustion
Line and branch coverage exceeds 95% for all critical contracts
Edge cases are tested: zero amounts, max values, empty arrays, single-element arrays
Fuzz testing (Foundry fuzz, Echidna, or Medusa) has been run on critical functions
Invariant testing verifies protocol invariants hold across random operation sequences
Fork testing against mainnet state validates real-world token and protocol interactions
Integration tests cover multi-contract interactions and cross-contract flows
Tests include attack scenarios: reentrancy attempts, flash loan attacks, sandwich attacks
Formal verification has been considered for the most critical invariants (Certora, Halmos)
Deployment scripts are version controlled and tested — not manual
Constructor arguments and initialization parameters are verified before deployment
Source code is verified on block explorers (Etherscan, etc.) immediately after deployment
Admin keys are stored in hardware wallets or multi-sig, never in hot wallets or plain text
Emergency pause functionality exists and has been tested
Protocol parameters (fees, limits, addresses) are documented and their valid ranges are enforced on-chain
Testnet deployment has been live for at least 2 weeks before mainnet
Real-time monitoring and alerting is configured for unusual activity (large withdrawals, governance changes)
An incident response plan exists with clear roles, communication channels, and procedures
War gaming has been conducted — the team has practiced responding to simulated exploits
A bug bounty program is live on a reputable platform (Immunefi, HackenProof, Code4rena)
Circuit breakers exist for rate-limiting large operations (e.g., max withdrawal per block)
Team members can be reached within 15 minutes during an incident via on-call rotation
Audit Workflow: When to Check What
During Development
Run automated scans on every commit. Categories 1-5 should be checked continuously. Use our free scanner to catch pattern-level issues early. Write tests that cover attack scenarios from categories 6-7. This is the cheapest time to find and fix bugs.
Pre-Deployment
All 12 categories should be fully checked. Run the complete checklist at least once. Commission a professional audit for protocols handling significant value. Categories 10-11 become critical. Allow 2-4 weeks for audit turnaround and another 1-2 weeks for fixes.
Post-Deployment
Category 12 is ongoing. Monitor continuously. Maintain your bug bounty. Re-audit after any code changes. Track emerging vulnerability classes and verify your protocol is not affected. The security landscape evolves — your monitoring must evolve with it.
Automated vs. Manual: Getting the Best of Both
This checklist contains over 80 items. Checking them all manually is time-consuming and error-prone. The most effective approach is layering automated and manual review:
Workflow
Development Phase:
1. Automated scanner on every commit // Catches ~40% of items
2. Unit + fuzz + invariant tests // Catches ~25% of items
3. Internal code review // Catches ~15% of items
Pre-Deployment Phase:
4. AI deep analysis ($99-$199) // Catches cross-contract issues
5. Professional manual audit // Catches business logic flaws
6. Full checklist walkthrough // Catches remaining ~20%
Ongoing:
7. Monitoring + bug bounty // Catches novel attacks
No single approach catches everything. Automated tools are fast and consistent but miss business logic. Manual auditors are thorough but expensive and slow. The combination is what gives you real confidence.
Start Scanning Now
The best time to start scanning is before you've written all the code. The Solari free scanner checks for reentrancy, access control, oracle manipulation, arithmetic issues, and many more vulnerability patterns from this checklist. Paste your Solidity code and get results in seconds.
For a comprehensive pre-deployment review that covers cross-contract interactions, economic attack modeling, and detailed remediation guidance, explore our paid scanning tiers starting at $99.