← All posts
OWASPAudit ProcessSmart Contracts

The OWASP Smart Contract Top 10 (2026), and How We Test Each One

Security Wiz team3 min read

The OWASP Smart Contract Top 10 is the closest thing the industry has to a shared checklist of how contracts get broken. The 2026 edition is based on analysis of 122 deduplicated incidents from 2025, which accounted for roughly $905 million in losses, and uses it to forecast which risks matter most this year.

Every audit we run tests all ten categories, and the report shows how each one was tested, including the ones where we found nothing. Here's what each means and how we go after it.

SC01: Access Control Vulnerabilities

Functions that move funds or change critical state can be called by the wrong party, because a permission check is missing, in the wrong place, or bypassable. Unprotected initializers are a perennial example. How we test: we map who can call every function, then try to call it as someone who shouldn't be able to, impersonating addresses on a fork.

SC02: Business Logic Vulnerabilities

The code does exactly what it says, but what it says is wrong: a broken invariant, a gap in the state machine, an economic assumption an attacker can abuse. No scanner finds these, because nothing is "wrong" in the syntax. How we test: we write down the invariants your protocol relies on ("total shares always equal total deposits") and turn them into fuzz and invariant tests, backed by human review.

SC03: Price Oracle Manipulation

A protocol that trusts a manipulable price source, such as a spot price from a thin pool or a stale feed, can be tricked into mispricing collateral, swaps, or liquidations. How we test: on a fork we attack against real pools and real liquidity, and test stale-oracle behavior directly.

SC04: Flash Loan–Facilitated Attacks

Capital borrowed and repaid within one transaction lets an attacker amplify a small flaw into a protocol-draining one. Flash loans aren't a vulnerability themselves. They make other vulnerabilities cheap to exploit. How we test: we run flash-loan attack scenarios on the fork against actual lending pools.

SC05: Lack of Input Validation

Parameters, addresses and calldata accepted without checks let attackers pass values the code never anticipated: zero addresses, unbounded amounts, mismatched array lengths. How we test: fuzzing with extreme inputs, plus static analysis for unchecked parameters.

SC06: Unchecked External Calls

Ignoring a return value, or trusting how another contract will behave, lets a failed or malicious call silently corrupt state. Non-standard tokens are a common trigger. How we test: we trace every external call, and test integrations with real tokens that charge fees, rebase, or block addresses.

SC07: Arithmetic Errors (Rounding and Precision)

Rounding direction and precision loss, repeated across many operations, can be farmed to leak value or break accounting. First-depositor share inflation is the best-known case. How we test: fuzzing with tiny and huge amounts, and checking that every division rounds in the protocol's favor.

SC08: Reentrancy Attacks

An external call lets the callee re-enter before state is updated, repeating a withdrawal or exploiting stale state across functions. It's old, well understood, and still showing up, now often as read-only reentrancy through view functions. How we test: static analysis for risky call ordering, then fork tests that actually try to re-enter.

SC09: Integer Overflow and Underflow

Arithmetic that wraps, in unchecked blocks, older compiler versions, or unsafe casts, produces wildly wrong balances or limits. Modern compilers catch most cases, so the remaining ones hide in places developers opted out of the checks. How we test: we flag every unchecked block and cast, and fuzz at the limits of each type.

SC10: Proxy and Upgradeability Vulnerabilities

Uninitialized implementations, storage layout collisions and unprotected upgrade paths let attackers take over or corrupt an upgradeable contract. Who holds the upgrade key matters as much as the code. How we test: we deploy on the fork exactly as your scripts do, check the final owners and admins, and test upgrade paths.

What a list can't cover

OWASP's list is deliberately about contract-level risk. Some of the worst losses start somewhere else: a bridge forging a message, a signature replayed across chains, a governance vote swung by borrowed voting power, or an interaction between your contract and a protocol you integrate with. Those need real on-chain state to test properly, which is why our Fork tier runs attacks against a fork of the live network rather than a mock.

You can read the full list at scs.owasp.org. If you'd like to see how your own contracts fare against all ten, request an audit.

Shipping something onchain?

Send us your repo and we’ll return a quote within 24 hours.

Request an Audit