Starknet Specialized Scanner

SkillCommunication

Use when the user wants to audit Starknet contracts for security vulnerabilities, scan Cairo contracts for Starknet-specific patterns including account abstraction, class replacement, or L1-L2 messaging, review Starknet DeFi protocols for component architecture flaws, or analyze cross-layer bridge security.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Starknet Specialized Scanner skill

What this skill tells your AI

The instructions your AI receives, as published by 0x-shashi/web3-audit-skills in skills/starknet-scanner/SKILL.md and read by ahel’s review.

Specialized security scanner for Starknet Cairo contracts. Extends the general Cairo Scanner with Starknet-specific patterns: account abstraction, contract upgrades via replace_class, component architecture, and the L1-L2 messaging bridge.


Why a Separate Starknet Scanner?

While the Cairo Scanner covers language-level patterns (felt arithmetic, Sierra safety), Starknet-specific features create unique attack surfaces:

FeatureSecurity Impact
Account AbstractionCustom validation logic = custom attack surface
replace_class_syscallContract upgrade mechanism — must be protected
Components (like Solidity libraries)Storage collision between components
L1-L2 MessagingCross-chain replay, message validation
SequencerCentralized sequencer = MEV, censorship risks
Fee marketSTRK token fees, gas estimation

Detection Capabilities

CategoryDetectionSeverity
Account__validate__ missing signature checkCritical
Account__execute__ allows arbitrary call without validationCritical
AccountSignature replay across chains (no chain_id in hash)High
Upgradereplace_class_syscall callable by unauthorized partyCritical
UpgradeNo upgrade delay/timelockHigh
UpgradeStorage layout incompatibility after upgradeHigh
ComponentsStorage collision between componentsHigh
ComponentsComponent events shadowing contract eventsMedium
L1-L2Message replay (consumed message not tracked)Critical
L1-L2Missing sender validation on L1 handlerCritical
L1-L2Message not consumed (stuck funds)High
FeltFelt arithmetic wrapping (p = 2^251 + 17*2^192 + 1)High
StorageStorage address collision (Pedersen hash)Medium
AccessMissing caller validation on external functionCritical
AccessOwnable component not initializedHigh

Starknet Account Abstraction

Every account on Starknet is a smart contract. This means custom validation logic:

#[starknet::contract(account)]
mod MyAccount {
    // REQUIRED: Validates transaction signature
    // If this returns successfully, the tx is considered valid
    #[external(v0)]
    fn __validate__(
        ref self: ContractState,
        calls: Array<Call>
    ) -> felt252 {
        // CRITICAL: Must verify the transaction signature
        // If this blindly returns VALIDATED, anyone can submit txs as this account
        let tx_hash = get_tx_info().unbox().transaction_hash;
        let signature = get_tx_info().unbox().signature;

        // Verify signature against stored public key
        assert(check_ecdsa_signature(tx_hash, self.public_key.read(), *signature.at(0), *signature.at(1)), 'invalid sig');

        starknet::VALIDATED
    }

    // REQUIRED: Executes the validated transaction
    #[external(v0)]
    fn __execute__(
        ref self: ContractState,
        calls: Array<Call>
    ) -> Array<Span<felt252>> {
        // Execute each call
        // Typically a loop over calls with call_contract_syscall
    }
}

Account Security Checklist

  • __validate__ verifies transaction hash signature
  • __validate__ uses stored public key (not hardcoded)
  • Signature cannot be replayed (nonce handled by protocol)
  • chain_id included in signature verification (cross-chain replay)
  • Key rotation mechanism exists and is secure
  • Multicall execution handles failures correctly (atomicity)

Contract Upgrade via replace_class_syscall

Starknet contracts can upgrade their logic using replace_class_syscall:

use starknet::replace_class_syscall;
use starknet::ClassHash;

#[external(v0)]
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
    // CRITICAL: WHO can call this?
    self.ownable.assert_only_owner();

    // Replace the contract's class (logic) with new implementation
    replace_class_syscall(new_class_hash).unwrap();

    // Emit upgrade event
    self.emit(Upgraded { new_class_hash });
}

Upgrade Security

RiskDescription
Unauthorized upgradeAnyone calling replace_class_syscall can change contract logic
No timelockInstant upgrade = no time for users to exit
Storage incompatibilityNew class may interpret storage differently
Proxy patternIf using proxy, verify replace_class on implementation, not just proxy
  • replace_class_syscall protected by access control (owner, governance)
  • Upgrade delay (timelock) implemented for critical contracts
  • Storage layout documented and verified compatible across versions
  • Upgrade event emitted

Component Architecture

Starknet components are reusable modules (similar to Solidity libraries with storage):

// Using OpenZeppelin components
#[starknet::contract]
mod MyContract {
    use openzeppelin::access::ownable::OwnableComponent;
    use openzeppelin::token::erc20::ERC20Component;

    component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
    component!(path: ERC20Component, storage: erc20, event: ERC20Event);

    #[storage]
    struct Storage {
        #[substorage(v0)]
        ownable: OwnableComponent::Storage,
        #[substorage(v0)]
        erc20: ERC20Component::Storage,
        // Custom storage
        my_value: felt252,
    }
}

Component Security

RiskDescription
Storage collisionTwo components writing to same storage address
Uninitialized componentOwnable without initializer() = no owner set
Event shadowingComponent events with same name as contract events
Version mismatchComponent version incompatible with contract
  • All components initialized in constructor
  • #[substorage(v0)] used correctly (automatic storage isolation)
  • No manual storage access that could collide with component storage
  • Component versions compatible with each other

L1-L2 Messaging

Starknet communicates with Ethereum L1 via asynchronous messaging:

DirectionMechanismLatency
L1 → L2send_message_to_l2() on Starknet Core contract~minutes (L2 block time)
L2 → L1send_message_to_l1_syscall() in Cairo~hours (proof verification)

L1-L2 Security Checklist

  • L2 handler validates L1 sender (from_address in L1Handler)
  • L1 handler validates L2 sender (message origin)
  • Messages consumed exactly once (replay protection)
  • Message format matches between L1 and L2 contracts
  • Stuck message handling (cancellation mechanism exists)
  • Fee handling on L1→L2 messages correct

Resources

Workflows

See Also

Error Code Reference

Starknet-specific error codes and system errors encountered during audits.

Starknet OS / Sequencer Errors

Error CodeNameMeaning
TRANSACTION_FAILEDTransaction failureGeneric execution failure — check inner error
ENTRYPOINT_NOT_FOUNDMissing entrypointSelector not found on contract — wrong function name/args
UNINITIALIZED_CONTRACTNo contractAddress has no deployed contract class
ENTRY_POINT_FAILEDExecution revertContract function reverted — check custom error
FEE_TRANSFER_FAILUREFee paymentInsufficient balance to pay transaction fee
VALIDATE_FAILUREAccount validationAccount __validate__ rejected transaction — signature/auth issue
OUT_OF_RESOURCESResource limitTransaction exceeded Cairo steps or builtins limit
CLASS_ALREADY_DECLAREDDuplicate classContract class hash already declared on network

Account Abstraction Errors

Error PatternSourceMeaning
'INVALID_SIGNATURE'__validate__Signature verification failed in account contract
'INVALID_CALLER'Account guardCaller is not the expected account or protocol
'INVALID_TX_VERSION'Version checkTransaction version not supported (v1 vs v3)
'EXPIRED'Time checkTransaction or session expired
'UNDERSPENT_FEE'Fee estimationActual fee lower than estimate — potential gas griefing
'PAYMASTER_REJECTED'PaymasterPaymaster refused to sponsor transaction

Starknet Contract Errors (OpenZeppelin Cairo)

Error StringComponentMeaning
'Caller is not the owner'OwnableComponentMissing owner role — access control
'Caller is the zero address'OwnableComponentInvalid zero caller
'New owner is the zero address'OwnableComponentInvalid ownership transfer
'ERC20: insufficient balance'ERC20ComponentToken balance too low
'ERC20: insufficient allowance'ERC20ComponentApproval not set
'ERC721: invalid token ID'ERC721ComponentToken does not exist
'ERC721: unauthorized caller'ERC721ComponentNot owner or approved
'ReentrancyGuard: reentrant call'ReentrancyGuardComponentReentrancy detected
'Class hash cannot be zero'UpgradeableComponentInvalid upgrade target

L1↔L2 Messaging Errors

Error PatternDirectionMeaning
'INVALID_MESSAGE_TO_CONSUME'L1→L2Message not found in L2 pending messages
'MESSAGE_NOT_SENT'L2→L1L2 message not recorded by sequencer
'INVALID_FROM_ADDRESS'L1→L2L1 sender address does not match expected
'INVALID_NONCE'BothMessage nonce mismatch — replay or ordering issue

Troubleshooting

IssueLikely CauseSolution
Account abstraction vulnerabilities missedScanner uses EOA mental modelAudit __validate__ and __execute__ in all account contracts; check signature schemes
replace_class upgrade risks not flaggedScanner doesn't track class replacementMap all replace_class_syscall calls; verify upgrade authority and timelock protections
Component storage collision missedScanner doesn't model Cairo component storageVerify component storage isolation; check for #[storage] field name conflicts across components
L1↔L2 message handling gapsScanner audits L2 in isolationAudit #[l1_handler] functions; trace message flow from L1 contract through Starknet OS
Fee estimation manipulation not caughtScanner doesn't model Starknet fee mechanismCheck __validate__ and __execute__ for fee-related assumptions; test with v3 transactions
Missing event emission in state changesScanner focuses on logic, not observabilityVerify all state-changing functions emit events; critical for off-chain indexing and monitoring

Signals

GitHub stars
60
Forks
10
Last commit
Feb 2026
Advanced
Catalog kind
skill
Gateway key
starknet-scanner
Source
github.com/0x-shashi/web3-audit-skills