Cairo Vulnerability Scanner
Trail of BitsOfficialPublished by Trail of Bits
- Skill
- Review and audit
- Security
- CC-BY-SA-4.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Cairo Vulnerability Scanner is a structured auditing framework designed to identify security risks specific to the Cairo language and the StarkNet ecosystem. It focuses on six critical vulnerability patterns, including arithmetic overflows, L1-L2 messaging issues, and signature replay attacks. The skill enforces a rigorous reporting process that requires a comprehensive coverage table, ensuring that every identified pattern is explicitly addressed, cleared, or marked as not applicable for the target contract.
What it does
- Scans Cairo source code for 6 specific security vulnerability patterns.
- Provides a mandatory coverage table to document the status of each vulnerability pattern.
- Offers specific mitigation strategies and code examples for identified security flaws.
- Integrates with static analysis tools like Caracal to automate detection.
- Validates L1-L2 bridge logic and cross-layer message handling.
- Ensures signature verification logic includes necessary replay protection.
When to use it
- During security audits of StarkNet smart contracts.
- When reviewing L1-L2 bridge implementations for potential vulnerabilities.
- As part of a pre-launch security assessment for Cairo-based applications.
- When validating signature verification and L1 handler logic.
Advantages
- Prevents incomplete audits by requiring a full coverage table for all 6 patterns.
- Focuses on platform-specific risks unique to the Cairo/StarkNet environment.
- Provides actionable remediation steps and code-level fixes.
- Standardizes the reporting format for security findings.
Usage examples
- “Audit my StarkNet contract in src/ for security vulnerabilities.”
- The agent will scan the codebase, generate a 6-row coverage table, and provide detailed reports for any found vulnerabilities with remediation advice.
- “Check my L1 handler implementation for potential security flaws.”
- The agent will specifically analyze the #[l1_handler] functions for from_address validation and access control issues.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/trailofbits/cairo-vulnerability-scanner/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip cairo-vulnerability-scanner.zip -d .agents/skills
Documentation by Trail of Bits
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_syscallProject Structure
src/contract.cairo- Main contract implementationsrc/lib.cairo- Library modulestests/- Contract testsScarb.toml- Cairo project configuration
Tool Support
Caracal: Trail of Bits static analyzer for Cairo
Installation:
cargo install --git https://github.com/crytic/caracal --profile release --force(a Rust tool — not on PyPI)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, above them a coverage table carrying a verdict for every pattern
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 ===6. 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.
Pattern Summary:
Felt252 Arithmetic Overflow/Underflow ⚠️ HIGH -
felt252wraps silently; useu128/u256L1 to L2 Address Conversion ⚠️ HIGH - L1 address not validated against STARKNET_FIELD_PRIME
L1 to L2 Message Failure ⚠️ HIGH - No cancellation path when a message cannot be consumed
Overconstrained L1 <-> L2 Interaction ⚠️ MEDIUM - Coupling that can strand funds or block progress
Signature Replay Protection ⚠️ HIGH - No nonce, or a domain separator missing chain/contract
Unchecked from_address in L1 Handler ⚠️ CRITICAL - Any L1 contract can drive the handler
For complete vulnerability patterns with code examples, see VULNERABILITY_PATTERNS.md.
7. Scanning Workflow
Step 1: Platform Identification
Verify Cairo language and StarkNet framework
Check Cairo version (Cairo 1.0+ vs legacy Cairo 0)
Locate contract files (
src/*.cairo)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 insteadStep 3: L1 Handler Analysis
For each #[l1_handler] function:
[ ] Validates
from_addressparameter[ ] 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-validation8. Reporting Format
Coverage Table
Report on every pattern in §6, whether or not it turned anything up. Emit this table above the findings, with all 6 rows present:
| # | Pattern | Verdict | Evidence |
|---|---|---|---|
| 1 | Felt252 Arithmetic Overflow/Underflow | clear | balances are u256; searched felt252 in arithmetic, none |
| 2 | L1 to L2 Address Conversion | ||
| 3 | L1 to L2 Message Failure | ||
| 4 | Overconstrained L1 <-> L2 Interaction | ||
| 5 | Signature Replay Protection | ||
| 6 | Unchecked from_address in L1 Handler |
Each verdict is one of:
found— citefile:lineand write the finding up in full below.clear— the pattern applies to this contract and the contract handles it. Name the function, trait, or check you searched for, so a reader can repeat the search.n/a— the pattern cannot apply here. Give the reason in one clause ("no L1 handlers in this contract"). Not having looked is notn/a.
A table with fewer than 6 rows is an incomplete scan and must be reported as one. A row whose Verdict cell is empty is incomplete in the same way: row 1 above is filled in to show the shape, and every row is filled in the same way before the report is done. Six clear verdicts is a
result a reader can act on. A report that covers two patterns and says nothing about the other four reads
exactly like a clean contract, and that is the failure this table exists to prevent.
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**:
```rust
// 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**:
1. Attacker deploys malicious L1 contract
2. Malicious contract calls `starknetCore.sendMessageToL2(l2Contract, selector, [attacker_address, 1000000])`
3. L2 handler processes message without checking sender
4. Attacker receives 1,000,000 tokens without depositing any funds
5. Protocol suffers infinite mint vulnerability
**Recommendation**:
Validate `from_address` against authorized L1 bridge:
```rust
#[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`9. 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)
10. 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: |
# Rebuilds from source each run; cache ~/.cargo or pin a release binary instead.
cargo install --git https://github.com/crytic/caracal --profile release --force
caracal detect src/ --fail-on high,critical11. Additional Resources
Building Secure Contracts:
building-secure-contracts/not-so-smart-contracts/cairo/Caracal: https://github.com/crytic/caracal
Cairo Documentation: https://book.cairo-lang.org/
StarkNet Documentation: https://docs.starknet.io/
OpenZeppelin Cairo Contracts: https://github.com/OpenZeppelin/cairo-contracts
12. Quick Reference Checklist
Before completing Cairo/StarkNet audit:
Arithmetic Safety (HIGH):
[ ] No felt252 used for balances/amounts (use u128/u256)
[ ] OR felt252 arithmetic has explicit bounds checking
[ ] Overflow/underflow scenarios tested
L1 Handler Security (CRITICAL):
[ ] ALL
#[l1_handler]functions validatefrom_address[ ] from_address compared against stored L1 contract address
[ ] Cannot bypass by deploying alternate L1 contract
L1-L2 Messaging (HIGH):
[ ] L1 bridge validates addresses < STARKNET_FIELD_PRIME
[ ] L1 bridge implements message cancellation
[ ] L2 handlers check from_address
[ ] Symmetric validation rules L1 ↔ L2
[ ] Full roundtrip flows tested
Signature Security (HIGH):
[ ] Signatures include nonce tracking
[ ] Nonce incremented after each use
[ ] Domain separator includes chain ID and contract address
[ ] Signature replay tested and prevented
[ ] Cross-chain replay prevented
Tool Usage:
[ ] Caracal scan completed with no critical findings
[ ] Unit tests cover all vulnerability scenarios
[ ] Integration tests verify L1-L2 flows
[ ] Testnet deployment tested before mainnet
[ ] Coverage table emitted with all 6 rows, each carrying a verdict of
found,clearorn/awith a reason
13. Rationalizations to Reject
"The contract is small, so most patterns obviously don't apply." Obvious to whom? An
n/acosts one clause and makes the judgment reviewable. Silence records nothing, and a reader cannot tell it apart from not having checked."Caracal reported nothing, so the contract is clean." Caracal covers a subset of these 6 patterns and does not reach the logic-level ones at all. A clean tool run is one row of evidence, not a verdict on the patterns it never examined. Say which patterns it covered.
"I checked the patterns that matter for this contract." Deciding which patterns matter is the scan, not a precondition for starting it. Rank by severity after the table is complete, not by leaving rows out.
"No findings, so there is nothing to report." A zero-finding scan still emits the full coverage table. That table is the deliverable: it is what distinguishes a contract that was examined from one that was glanced at.
"Cairo 1 has native overflow checks, so arithmetic is safe." Name the types.
felt252does not behave like the sized integer types, and the boundary between them is where pattern 4 lives."The L1 side validates that." Then cite the L1 contract. A check you believe exists across the bridge is an assumption until you have read it, and unverified
from_addressis the canonical StarkNet bridge bug.
Files
- ATTRIBUTION.mdAdded by AutoGineer973 B
- LICENSELicence file added by AutoGineer19.7 KiB
- SKILL.md12.8 KiB
- agents/openai.yaml259 B
- assets/trail-of-bits-mark.svg3.0 KiB
- resources/VULNERABILITY_PATTERNS.md20.8 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Trail of Bits
- Publisher
- Trail of Bits (Official)
- Source
- trailofbits/skills · plugins/building-secure-contracts/skills/cairo-vulnerability-scanner · commit e4dd0bb
- Licence
- Creative Commons Attribution-ShareAlike 4.0 International (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Trail of Bits or Trail of Bits.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cairo-vulnerability-scanner.zip