#01 SC01:2026 Critical Held #1

Access Control Vulnerabilities

Improper access control describes any situation where a smart contract does not rigorously enforce who may invoke privileged behavior, under which conditions, and with which parameters.

Official OWASP description, from scs.owasp.org (CC BY-NC-SA 4.0).

$220M
2025 losses attributed
24.3%
Of all 2025 SC losses
30
Recorded 2025 incidents

Why this rank in 2026

Held #1. Practitioner survey ranks access control as the most consequential risk, and the 2025 dataset confirms it: ~$220M lost across 30 separate incidents, including the Balancer V2 manageUserBalance bug (~$128M) and the Zoth compromised-deployer attack ($8.4M).

What "access control" actually covers

OWASP defines this category as any failure to rigorously enforce who may invoke privileged behavior, under which conditions, and with which parameters. That's broader than missing onlyOwner modifiers. In practice, the category covers six distinct failure modes:

  • Missing or wrong modifiers on sensitive functions.

  • Caller validation against user-supplied values instead of msg.sender.

  • Unprotected initialization, including proxies that remain re-initializable.

  • Single-EOA admins with no multisig or timelock.

  • Privilege confusion across modules or cross-chain trust boundaries.

  • Missing validation on hook and callback entry points (e.g. Uniswap V4 onlyPoolManager).

Why it's still #1 in 2026

Access control held the top spot in OWASP's 2026 ranking because it produced both the highest frequency (30 incidents in the 2025 dataset) and one of the highest dollar totals (~$220M). Two incidents define the year:

  • Balancer V2 (Nov 2025) lost ~$128M when the manageUserBalance function allowed attackers to set op.sender values that bypassed the intended caller check. (OWASP also cross-references this incident under SC07 because rounding amplified the exploit.)

  • Zoth (Mar 2025) lost $8.4M when a compromised deployer EOA was used to upgrade USD0PPSubVaultUpgradeable to a malicious implementation. That's a SC10 root cause (proxy upgrade) executed through an SC01 failure (single-EOA admin without multisig).

  • Cork Protocol (May 2025) lost $11M-$12M because Uniswap V4 hook callbacks lacked onlyPoolManager validation.

How AI auditors handle this category

EVMbench and related benchmarks show frontier LLMs catching the static version of this bug class reliably - missing modifiers, tx.origin use, public functions that should be internal. Where they still struggle is the systemic version: privileges that are technically present but wrong, modules that grant each other authority transitively, and hook/callback patterns where the caller should be a specific protocol-managed address. Those still need a human auditor who can model the trust graph.

See the SCH attack analysis at /attacks/access-control for a deeper walk-through of the patterns above.

Vulnerable vs secure code

✗ Vulnerable solidity
// Vulnerable: no caller validation on a privileged function
contract Vault {
    address public owner;
    uint256 public totalAssets;

    function withdrawTo(address to, uint256 amount) external {
        // Missing: require(msg.sender == owner, "not owner");
        totalAssets -= amount;
        (bool ok, ) = to.call{value: amount}("");
        require(ok, "transfer failed");
    }
}
✓ Secure solidity
// Secure: OpenZeppelin AccessControl + checks-effects-interactions
import "@openzeppelin/contracts/access/AccessControl.sol";

contract Vault is AccessControl {
    bytes32 public constant TREASURER_ROLE = keccak256("TREASURER_ROLE");
    uint256 public totalAssets;

    constructor(address admin) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(TREASURER_ROLE, admin);
    }

    function withdrawTo(address to, uint256 amount)
        external onlyRole(TREASURER_ROLE)
    {
        require(to != address(0), "zero address");
        require(amount <= totalAssets, "insufficient");
        totalAssets -= amount;                          // effect
        (bool ok, ) = to.call{value: amount}("");       // interaction
        require(ok, "transfer failed");
        emit Withdrawn(msg.sender, to, amount);
    }
}

AI vs human auditor on this category

Each bar is a detection rate: out of 100 known access control bugs, how many that auditor type finds. Higher means more reliable. The gap below is the percentage-point difference - the work senior humans still do that AI does not.

AI auditor (frontier LLM)
75%
Human auditor (senior)
92%

% of SC01 bugs caught - higher is better.

Human advantage on SC01
+17 percentage points
Senior auditors catch 17 more access control bugs per 100 than frontier AI today. That gap is the skill the SCH course teaches.

AI auditors reliably flag missing access modifiers and tx.origin patterns, but they routinely miss cross-module privilege confusion and hook/callback validation. Humans still win on system-level reasoning across modules.

Methodology: EVMbench, Cecuro purpose-built agent benchmarks, and senior-auditor self-reported catch rates. SCH editorial, not OWASP-authored.

Prevention checklist

  • Use OpenZeppelin Ownable or AccessControl instead of hand-rolled role systems.
  • Hold privileged roles in a multisig or governance contract, never a single EOA.
  • Lock initializers with the initializer / reinitializer modifiers.
  • Emit events for every privilege change and upgrade so monitors can react.
  • Encode access policies as invariants in tests and fuzzing properties.
  • Validate caller identity on hook and callback entry points (e.g. onlyPoolManager).

Detection tools

Industry-standard tools that detect this category. Tool mappings are SCH editorial - OWASP's per-category pages do not list specific tools.

Slither
static

incorrect-modifier, unprotected-upgrade, tx-origin, arbitrary-send, missing-zero-check

Mythril
symbolic

symbolic execution finds unprotected privileged functions

Aderyn
static

centralization-risk, unprotected-initializer detectors

Semgrep
lint

custom rulesets for missing access modifiers

FAQ

What is OWASP SC01 Access Control Vulnerabilities?
SC01 is the #1 entry in the OWASP Smart Contract Top 10 2026. It covers any failure to rigorously enforce who may invoke privileged behavior in a smart contract, under which conditions, and with which parameters. The category ranges from missing onlyOwner modifiers and tx.origin checks to cross-module privilege confusion and uninitialized proxy admins.
Why did access control stay #1 in OWASP 2026?
The 2025 incident dataset showed access control causing roughly $220M in losses across 30 separate hacks - the highest frequency and one of the highest dollar totals of any category. Both the OWASP practitioner survey and the on-chain loss data placed it at #1, with the Balancer V2 manageUserBalance bug (~$128M, Nov 2025) cited as the marquee 2025 incident.
What is the most common smart contract access control bug?
Missing or wrong modifiers on sensitive functions, especially around upgrade, mint, withdraw, and initialization paths. Other common variants include caller validation against user-supplied values instead of msg.sender, unprotected initializers on proxy implementations, and single-EOA admins with no multisig or timelock guarding upgrades.
How do auditors detect smart contract access control bugs?
Static tools (Slither, Aderyn, Semgrep) catch missing modifiers, tx.origin, unprotected upgrades, and missing zero-address checks. Symbolic execution (Mythril) finds unprotected privileged functions. Human auditors are still required for cross-module privilege confusion, hook/callback validation, and trust-graph reasoning across modules and chains.
Can AI auditors detect access control vulnerabilities?
AI auditors handle simple cases well (catch rate around 75% on EVMbench-style tests) - missing modifiers, tx.origin, public functions that should be internal. They routinely miss cross-module privilege issues, hook/callback validation in Uniswap V4-style architectures, and protocol-specific trust assumptions. Senior human auditors still detect roughly 92% of cases.
How do you prevent access control vulnerabilities in Solidity?
Use OpenZeppelin AccessControl or Ownable instead of hand-rolled role systems, hold privileged roles in a multisig or governance contract, lock initializers with the initializer / reinitializer modifiers, emit events on every privilege change, encode access policies as fuzzing invariants, and validate caller identity on hook and callback entry points (for example onlyPoolManager in Uniswap V4 hooks).

Master the techniques that make this category exploitable

The SCH Smart Contract Hacking Course teaches the exploit primitives, audit techniques, and tool workflows for access control vulnerabilities and every other OWASP 2026 category.