Most exploited contracts in 2023β2024 had been audited. The problem isn't that auditors missed a line of code β it's that the audit scope didn't include the actual attack surface. The majority of nine-figure exploits (Euler, Mango Markets, Multichain) involved economic logic bugs, cross-contract composability failures, or privileged-role compromises β none of which are reliably caught by line-by-line Solidity review alone. An audit is only as good as its threat model. Here's what to actually evaluate.
Specification vs. Implementation Bugs
The most consequential audit failures stem from a category most checklists don't name: specification bugs β where the code does exactly what it was written to do, but what it was written to do is wrong.
- Implementation bugs are what static analysis catches: reentrancy, unchecked return values, storage collisions. These are well-catalogued. Slither, Aderyn, and similar tools flag most of them.
- Specification bugs require the auditor to understand what the protocol should do, then verify the code achieves it. Example: a lending protocol's liquidation threshold is implemented correctly per the spec, but the spec itself allows positions to become underwater faster than liquidators can act during volatility. The code is correct; the design is exploitable.
- The gap between these two categories is where most post-audit exploits live. If the audit firm didn't receive or build a specification model, they can only catch implementation bugs.
When reviewing an audit report, check whether the scope section mentions invariant definitions or economic model review. If it only lists files and LOC count, the specification layer was likely unexamined.
Cross-Contract Interaction Surfaces
Single-contract analysis is necessary but insufficient. The real attack surface lives at the boundaries.
- External call ordering: Any function that makes external calls before updating state is a textbook reentrancy vector, but the modern version is subtler β cross-protocol reentrancy where the callback goes through a different protocol's contract (the Curve/Vyper reentrancy of July 2023 exploited this via read-only reentrancy on price oracles).
- Composability assumptions: Protocol A assumes Protocol B's token behaves like a standard ERC-20. Protocol B has a transfer hook. The audit of Protocol A in isolation never surfaces this. Look for whether the audit explicitly tested against the actual external contracts the protocol integrates with, not just interfaces.
- Delegate call proxies: UUPS and Transparent Proxy patterns introduce upgrade-related attack surfaces. The uninitialized implementation contract vulnerability (as seen in the Wormhole exploit) is a direct consequence of proxy architecture. An audit should verify that the implementation contract's initializer cannot be called by an arbitrary address.
- Flash loanβaccessible state: Any state that can be meaningfully manipulated within a single transaction β oracle prices, pool reserves, governance vote weight β is flash-loan vulnerable. The audit should identify every state variable readable by external contracts and assess its manipulability within an atomic transaction.
Economic Invariant Analysis
This is the discipline most audits underweight. Economic invariants are properties that must hold true across all possible state transitions β total supply consistency, collateral ratio floors, monotonicity of share price in vault tokens.
- A vault's share price should never decrease except through explicit loss-recognition mechanisms. If a sequence of deposits and withdrawals can extract more value than was deposited, the invariant is broken. This is the rounding-error exploit class that hit multiple ERC-4626 vaults in 2023.
- For AMMs, the constant-product (or constant-sum, or concentrated liquidity) invariant must hold after every swap, mint, and burn β including when fees are extracted. Auditors should verify the invariant holds at boundary values: zero liquidity, maximum tick range, single-wei amounts.
- For lending markets, the solvency invariant β total borrows must never exceed realizable collateral value β should be tested under oracle failure, extreme price movement, and liquidation cascade scenarios.
Formal verification tools like Certora and Halmos can prove invariants hold across all reachable states, not just tested ones. If a protocol handles significant value and its audit didn't include formal verification of at least its core invariants, that's a gap.
Privileged Roles and Upgrade Mechanisms
Admin keys are not a code vulnerability, but they are the single most common root cause of total fund loss.
- Identify every address with privileged access: owner, admin, guardian, pauser, upgrader. Map what each role can do. If any single role can drain funds or modify core logic, the contract's trust model depends entirely on operational security, not code.
- Timelocks mitigate but don't eliminate this risk. A 48-hour timelock on upgrades is meaningful only if monitoring infrastructure exists to detect queued transactions and users have realistic exit paths. Many timelocks are set to values short enough (6β24 hours) that they provide minimal practical protection.
- Multisig configurations matter: a 2-of-3 multisig on a protocol holding $500M is a structural risk regardless of code quality. The audit should document the governance structure even if it can't change it.
- The Multichain exploit ($126M, July 2023) was a compromised private key with excessive permissions. No code audit catches this, but a good audit flags the risk surface.
What Static Analysis Catches (and Doesn't)
Static analysis tools β Slither, Mythril, Aderyn β are a baseline, not a substitute for manual review.
- They reliably catch: reentrancy (simple patterns), unchecked low-level calls, unused return values, storage collision in proxies, basic access control omissions, integer issues (less relevant post-Solidity 0.8.0 default checks).
- They reliably miss: business logic errors, economic exploits, cross-contract interaction bugs, oracle manipulation, governance attacks, and anything that requires understanding intent rather than syntax.
- A common failure mode: audit reports that list dozens of "informational" and "low" findings from static analysis, creating the appearance of thoroughness, while missing a single critical logic flaw. Volume of findings is not signal.
Reading an Audit Report Critically
The audit report itself is an artifact worth auditing.
- Scope completeness: Compare the audited commit hash and file list against the deployed contracts. If the protocol added files or changed code after the audit, the report doesn't cover what's live. Verify this on-chain β check the deployed bytecode against the audited source.
- Finding severity calibration: Firms classify differently. A "medium" at Trail of Bits might be a "critical" at a less experienced firm. Read the actual finding descriptions, not just the severity labels.
- Remediation verification: Check whether the report includes a re-review of fixes. Many reports note findings but don't confirm they were resolved. An "acknowledged" status on a high-severity finding means the team chose not to fix it β that's a conscious risk acceptance you should evaluate.
- What's absent: No mention of oracle manipulation analysis in a DeFi protocol is itself a finding. No mention of MEV exposure in a DEX audit is a gap. The absence of certain analyses is as informative as their presence.
Failure Modes and Real-World Attack Patterns
- Price oracle manipulation: Protocols using spot AMM prices (reserve ratios) as oracles are exploitable via flash loans. TWAP oracles resist single-block manipulation but are vulnerable to multi-block manipulation, especially post-Merge where consecutive block proposers can manipulate across blocks. Chainlink feeds introduce liveness risk β stale prices during network congestion can enable bad liquidations.
- Governance attacks: Flash loan governance (borrow tokens β vote β return) has been demonstrated. Compound-style timelock governance with token-weighted voting is vulnerable if token distribution is concentrated. Check vote delegation patterns and quorum thresholds.
- Precision loss and rounding: Solidity's integer-only math means every division truncates. In vault share calculations, an attacker who is the first depositor can donate assets to inflate the share price, causing subsequent depositors to receive zero shares. The standard mitigation β virtual shares/assets or a minimum initial deposit β should be present in any ERC-4626 vault.
- Denial of service via gas griefing: Unbounded loops over user-controlled arrays can make functions uncallable. This has bricked withdrawal functions in NFT mints and reward distribution contracts.
- Storage layout corruption in upgrades: Adding, removing, or reordering state variables between proxy implementation versions corrupts storage. OpenZeppelin's storage gap pattern mitigates this but requires discipline across every upgrade.
Verify / Go Deeper
- [Ethereum Smart Contract Best Practices](https://consensys.github.io/smart-contract-best-practices/) β ConsenSys Diligence's maintained reference
- [SWC Registry](https://swcregistry.io/) β Standardized weakness classification for Solidity, with test cases
- [Rekt.news Leaderboard](https://rekt.news/leaderboard/) β Primary source for post-mortem analysis of exploits, sorted by value lost
- [Solodit](https://solodit.xyz/) β Aggregated audit findings across firms, searchable by vulnerability class
- [Certora Documentation](https://docs.certora.com/) β For understanding formal verification of economic invariants
- Verify deployed bytecode against audited source using Etherscan's contract verification or Sourcify