cairo-vulnerability-scanner

Scans Cairo/StarkNet smart contracts for 6 critical vulnerabilities including felt252 arithmetic overflow, L1-L2 messaging issues, and signature replay attacks. Detects 6 vulnerability patterns: unchecked arithmetic, storage collision, missing access control, improper felt252 boundaries, unvalidated contract addresses, and missing caller validation Analyzes L1 handler functions for unvalidated from_address parameters and L1-L2 bridge implementations for cross-layer messaging vulnerabilities Integrates with Caracal static analyzer for automated detection and provides detailed findings with vulnerable code snippets and remediation examples Includes testing recommendations, priority guidelines, and a pre-deployment security checklist for StarkNet projects

INSTALLATION
npx skills add https://github.com/trailofbits/skills --skill cairo-vulnerability-scanner
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Cairo/StarkNet Vulnerability Scanner

1. Purpose

Systematically scan Cairo smart contracts on StarkNet for platform-specific security vulnerabilities related to arithmetic, cross-layer messaging, and cryptographic operations. This skill encodes 6 critical vulnerability patterns unique to Cairo/StarkNet ecosystem.

2. When to Use This Skill

  • Auditing StarkNet smart contracts (Cairo)
  • Reviewing L1-L2 bridge implementations
  • Pre-launch security assessment of StarkNet applications
  • Validating cross-layer message handling
  • Reviewing signature verification logic
  • Assessing L1 handler functions

3. Platform Detection

File Extensions & Indicators

  • Cairo files: .cairo

Language/Framework Markers

// Cairo contract indicators

#[contract]

mod MyContract {

    use starknet::ContractAddress;

    #[storage]

    struct Storage {

        balance: LegacyMap<ContractAddress, felt252>,

    }

    #[external(v0)]

    fn transfer(ref self: ContractState, to: ContractAddress, amount: felt252) {

        // Contract logic

    }

    #[l1_handler]

    fn handle_deposit(ref self: ContractState, from_address: felt252, amount: u256) {

        // L1 message handler

    }

}

// Common patterns

felt252, u128, u256

ContractAddress, EthAddress

#[external(v0)], #[l1_handler], #[constructor]

get_caller_address(), get_contract_address()

send_message_to_l1_syscall

Project Structure

  • src/contract.cairo - Main contract implementation
  • src/lib.cairo - Library modules
  • tests/ - Contract tests
  • Scarb.toml - Cairo project configuration

Tool Support

  • Caracal: Trail of Bits static analyzer for Cairo
  • Installation: pip install caracal
  • Usage: caracal detect src/
  • cairo-test: Built-in testing framework
  • Starknet Foundry: Testing and development toolkit

4. How This Skill Works

When invoked, I will:

  • Search your codebase for Cairo files
  • Analyze each contract for the 6 vulnerability patterns
  • Report findings with file references and severity
  • Provide fixes for each identified issue
  • Check L1-L2 interactions for messaging vulnerabilities

5. Example Output

When vulnerabilities are found, you'll get a report like this:

=== CAIRO/STARKNET VULNERABILITY SCAN RESULTS ===

---

## 5. Vulnerability Patterns (6 Patterns)

I check for 6 critical vulnerability patterns unique to Cairo/Starknet. For detailed detection patterns, code examples, mitigations, and testing strategies, see [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md).

### Pattern Summary:

1. **Unchecked Arithmetic** ⚠️ CRITICAL - Integer overflow/underflow in felt252

2. **Storage Collision** ⚠️ CRITICAL - Conflicting storage variable hashes

3. **Missing Access Control** ⚠️ CRITICAL - No caller validation on sensitive functions

4. **Improper Felt252 Boundaries** ⚠️ HIGH - Not validating felt252 range

5. **Unvalidated Contract Address** ⚠️ HIGH - Using untrusted contract addresses

6. **Missing Caller Validation** ⚠️ CRITICAL - No get_caller_address() checks

For complete vulnerability patterns with code examples, see [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md).

## 5. Scanning Workflow

### Step 1: Platform Identification

1. Verify Cairo language and StarkNet framework

2. Check Cairo version (Cairo 1.0+ vs legacy Cairo 0)

3. Locate contract files (`src/*.cairo`)

4. Identify L1-L2 bridge contracts (if applicable)

### Step 2: Arithmetic Safety Sweep

Find felt252 usage in arithmetic

rg "felt252" src/ | rg "[-+*/]"

Find balance/amount storage using felt252

rg "felt252" src/ | rg "balance|amount|total|supply"

Should prefer u128, u256 instead


### Step 3: L1 Handler Analysis

For each `#[l1_handler]` function:

-  Validates `from_address` parameter

-  Checks address != zero

-  Has proper access control

-  Emits events for monitoring

### Step 4: Signature Verification Review

For signature-based functions:

-  Includes nonce tracking

-  Nonce incremented after use

-  Domain separator includes chain ID and contract address

-  Cannot replay signatures

### Step 5: L1-L2 Bridge Audit

If contract includes bridge functionality:

-  L1 validates address < STARKNET_FIELD_PRIME

-  L1 implements message cancellation

-  L2 validates from_address in handlers

-  Symmetric access controls L1 ↔ L2

-  Test full roundtrip flows

### Step 6: Static Analysis with Caracal

Run Caracal detectors

caracal detect src/

Specific detectors

caracal detect src/ --detectors unchecked-felt252-arithmetic

caracal detect src/ --detectors unchecked-l1-handler-from

caracal detect src/ --detectors missing-nonce-validation


## 6. Reporting Format

### Finding Template

[CRITICAL] Unchecked from_address in L1 Handler

Location: src/bridge.cairo:145-155 (handle_deposit function)

Description:

The handle_deposit L1 handler function does not validate the from_address parameter. Any L1 contract can send messages to this function and mint tokens for arbitrary users, bypassing the intended L1 bridge access controls.

Vulnerable Code:


// bridge.cairo, line 145

#[l1_handler]

fn handle_deposit(

    ref self: ContractState,

    from_address: felt252,  // Not validated!

    user: ContractAddress,

    amount: u256

) {

    let current_balance = self.balances.read(user);

    self.balances.write(user, current_balance + amount);

}

Attack Scenario:

  • Attacker deploys malicious L1 contract
  • Malicious contract calls starknetCore.sendMessageToL2(l2Contract, selector, [attacker_address, 1000000])
  • L2 handler processes message without checking sender
  • Attacker receives 1,000,000 tokens without depositing any funds
  • Protocol suffers infinite mint vulnerability

Recommendation:

Validate from_address against authorized L1 bridge:

#[l1_handler]

fn handle_deposit(

    ref self: ContractState,

    from_address: felt252,

    user: ContractAddress,

    amount: u256

) {

    // Validate L1 sender

    let authorized_l1_bridge = self.l1_bridge_address.read();

    assert(from_address == authorized_l1_bridge, 'Unauthorized L1 sender');

    let current_balance = self.balances.read(user);

    self.balances.write(user, current_balance + amount);

}

References:

  • building-secure-contracts/not-so-smart-contracts/cairo/unchecked_l1_handler_from
  • Caracal detector: unchecked-l1-handler-from
---

## 7. Priority Guidelines

### Critical (Immediate Fix Required)

- Unchecked from_address in L1 handlers (infinite mint)

- L1-L2 address conversion issues (funds to zero address)

### High (Fix Before Deployment)

- Felt252 arithmetic overflow/underflow (balance manipulation)

- Missing signature replay protection (replay attacks)

- L1-L2 message failure without cancellation (locked funds)

### Medium (Address in Audit)

- Overconstrained L1-L2 interactions (trapped funds)

---

## 8. Testing Recommendations

### Unit Tests

#[cfg(test)]

mod tests {

use super::*;

#[test]

fn test_felt252_overflow() {

// Test arithmetic edge cases

}

#[test]

#[should_panic]

fn test_unauthorized_l1_handler() {

// Wrong from_address should fail

}

#[test]

fn test_signature_replay_protection() {

// Same signature twice should fail

}

}


### Integration Tests (with L1)

// Test full L1-L2 flow

#[test]

fn test_deposit_withdraw_roundtrip() {

// 1. Deposit on L1

// 2. Wait for L2 processing

// 3. Verify L2 balance

// 4. Withdraw to L1

// 5. Verify L1 balance restored

}


### Caracal CI Integration

.github/workflows/security.yml

  • name: Run Caracal

run: |

pip install caracal

caracal detect src/ --fail-on high,critical

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card