Skip to content
Security

Five pitfalls we keep finding in smart contract audits

Patterns that recur across audits we've shipped — anonymized, generalized, and useful before you ship.

Author
Mozaca Labs · Audit team
Published
March 15, 2026
Read time
8 min read

Most of the high-severity findings in the audits we ship cluster around the same five patterns. None of them are new. All of them are still in production code we receive for review. If your team is preparing for an audit, scrub for these first.

01 / 05

1. Re-entrancy on non-obvious paths

Most teams now defend the obvious withdraw paths. The pitfall is in less-obvious external calls — token hooks, callback receivers, upgrade proxies — where state mutation happens after a call returns.

02 / 05

2. Oracle staleness with no upper bound

Heartbeat checks are common; max-age checks are not. Without an upper bound on staleness, your protocol can settle against price data minutes old in degraded conditions.

03 / 05

3. Access control via address rather than role

Hardcoding privileged addresses is fragile. Use OpenZeppelin AccessControl with roles and document who holds what role, when it can be transferred, and what the emergency revocation path is.

04 / 05

4. Insufficient invariants under fuzzing

Most audits now include fuzzing. The quality of fuzzing depends entirely on the invariants you write. Generic invariants find generic bugs. Protocol-specific invariants — that capture what your system promises users — find protocol-specific bugs.

05 / 05

5. Upgrade paths without rehearsal

Storage layouts, initializers, ownership transfers — every upgrade is an opportunity to lose money. Rehearse upgrades on a forked mainnet. Document the rollback path before deploying.

End · Mozaca Labs · Audit team
Build with us

Have a system worth building?

Brief us on the seam you’re trying to engineer.