cairo-vulnerability-scanner

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cairo/StarkNet Vulnerability Scanner

Cairo/StarkNet漏洞扫描工具

1. Purpose

1. 用途

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.
系统性扫描StarkNet上的Cairo智能合约,查找与算术运算、跨层消息传递和加密操作相关的平台特定安全漏洞。本技能涵盖了Cairo/StarkNet生态系统特有的6种关键漏洞模式。

2. When to Use This Skill

2. 何时使用本技能

  • 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
  • 审计StarkNet智能合约(Cairo)
  • 审查L1-L2桥接实现
  • StarkNet应用上线前的安全评估
  • 验证跨层消息处理逻辑
  • 审查签名验证逻辑
  • 评估L1处理函数

3. Platform Detection

3. 平台检测

File Extensions & Indicators

文件扩展名与识别标志

  • Cairo files:
    .cairo
  • Cairo文件
    .cairo

Language/Framework Markers

语言/框架标记

rust
// 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
rust
// 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
  • src/contract.cairo
    - 主合约实现
  • src/lib.cairo
    - 库模块
  • tests/
    - 合约测试
  • Scarb.toml
    - Cairo项目配置文件

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

  • Caracal: Trail of Bits推出的Cairo静态分析器
  • 安装:
    pip install caracal
  • 使用:
    caracal detect src/
  • cairo-test: 内置测试框架
  • Starknet Foundry: 测试与开发工具包

4. How This Skill Works

4. 本技能工作原理

When invoked, I will:
  1. Search your codebase for Cairo files
  2. Analyze each contract for the 6 vulnerability patterns
  3. Report findings with file references and severity
  4. Provide fixes for each identified issue
  5. Check L1-L2 interactions for messaging vulnerabilities

调用本技能时,我会:
  1. 搜索代码库中的Cairo文件
  2. 分析每个合约,查找6种漏洞模式
  3. 报告检测结果,包含文件引用和风险等级
  4. 提供修复方案针对每个发现的问题
  5. 检查L1-L2交互中的消息传递漏洞

5. Example Output

5. 示例输出

When vulnerabilities are found, you'll get a report like this:
=== CAIRO/STARKNET VULNERABILITY SCAN RESULTS ===


---
当检测到漏洞时,你将收到如下报告:
=== CAIRO/STARKNET VULNERABILITY SCAN RESULTS ===


---

5. Vulnerability Patterns (6 Patterns)

5. 漏洞模式(6种)

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.
我会检查Cairo/Starknet特有的6种关键漏洞模式。如需详细的检测模式、代码示例、缓解措施和测试策略,请查看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.
  1. 未检查的算术运算 ⚠️ 严重 - felt252中的整数溢出/下溢
  2. 存储冲突 ⚠️ 严重 - 存储变量哈希冲突
  3. 缺失访问控制 ⚠️ 严重 - 敏感函数未验证调用者
  4. 不当的Felt252边界 ⚠️ 高风险 - 未验证felt252范围
  5. 未验证的合约地址 ⚠️ 高风险 - 使用不可信的合约地址
  6. 缺失调用者验证 ⚠️ 严重 - 未执行get_caller_address()检查
如需包含代码示例的完整漏洞模式,请查看VULNERABILITY_PATTERNS.md

5. Scanning Workflow

5. 扫描流程

Step 1: Platform Identification

步骤1:平台识别

  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)
  1. 验证Cairo语言和StarkNet框架
  2. 检查Cairo版本(Cairo 1.0+ 对比旧版Cairo 0)
  3. 定位合约文件(
    src/*.cairo
  4. 识别L1-L2桥接合约(如适用)

Step 2: Arithmetic Safety Sweep

步骤2:算术安全扫描

bash
undefined
bash
undefined

Find felt252 usage in arithmetic

查找算术运算中的felt252使用

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

Find balance/amount storage using felt252

查找使用felt252的余额/金额存储

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

Should prefer u128, u256 instead

应优先使用u128, u256

undefined
undefined

Step 3: L1 Handler Analysis

步骤3:L1处理函数分析

For each
#[l1_handler]
function:
  • Validates
    from_address
    parameter
  • Checks address != zero
  • Has proper access control
  • Emits events for monitoring
针对每个
#[l1_handler]
函数:
  • 验证
    from_address
    参数
  • 检查地址不为零
  • 具备适当的访问控制
  • 触发事件以便监控

Step 4: Signature Verification Review

步骤4:签名验证审查

For signature-based functions:
  • Includes nonce tracking
  • Nonce incremented after use
  • Domain separator includes chain ID and contract address
  • Cannot replay signatures
针对基于签名的函数:
  • 包含随机数(nonce)跟踪
  • 使用后递增随机数
  • 域分隔符包含链ID和合约地址
  • 防止签名重放

Step 5: L1-L2 Bridge Audit

步骤5:L1-L2桥接审计

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
如果合约包含桥接功能:
  • L1验证地址 < STARKNET_FIELD_PRIME
  • L1实现消息取消机制
  • L2处理函数验证from_address
  • L1 ↔ L2采用对称访问控制
  • 测试完整的往返流程

Step 6: Static Analysis with Caracal

步骤6:使用Caracal进行静态分析

bash
undefined
bash
undefined

Run Caracal detectors

运行Caracal检测器

caracal detect src/
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

---
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

6. 报告格式

Finding Template

检测结果模板

markdown
undefined
markdown
undefined

[CRITICAL] Unchecked from_address in L1 Handler

[严重] L1处理函数中未检查from_address

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

---
位置:
src/bridge.cairo:145-155
(handle_deposit函数)
描述:
handle_deposit
L1处理函数未验证
from_address
参数。任何L1合约都可以向该函数发送消息,为任意用户铸造代币,绕过预期的L1桥接访问控制。
漏洞代码:
rust
// bridge.cairo, line 145
#[l1_handler]
fn handle_deposit(
    ref self: ContractState,
    from_address: felt252,  // 未验证!
    user: ContractAddress,
    amount: u256
) {
    let current_balance = self.balances.read(user);
    self.balances.write(user, current_balance + amount);
}
攻击场景:
  1. 攻击者部署恶意L1合约
  2. 恶意合约调用
    starknetCore.sendMessageToL2(l2Contract, selector, [attacker_address, 1000000])
  3. L2处理函数在未检查发送者的情况下处理消息
  4. 攻击者无需存入任何资金即可获得1,000,000枚代币
  5. 协议遭受无限铸造漏洞
修复建议: 针对授权的L1桥接验证
from_address
:
rust
#[l1_handler]
fn handle_deposit(
    ref self: ContractState,
    from_address: felt252,
    user: ContractAddress,
    amount: u256
) {
    // 验证L1发送者
    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);
}
参考资料:
  • building-secure-contracts/not-so-smart-contracts/cairo/unchecked_l1_handler_from
  • Caracal检测器:
    unchecked-l1-handler-from

---

7. Priority Guidelines

7. 优先级指南

Critical (Immediate Fix Required)

严重(需立即修复)

  • Unchecked from_address in L1 handlers (infinite mint)
  • L1-L2 address conversion issues (funds to zero address)
  • L1处理函数中未检查from_address(无限铸造)
  • L1-L2地址转换问题(资金转入零地址)

High (Fix Before Deployment)

高风险(部署前修复)

  • Felt252 arithmetic overflow/underflow (balance manipulation)
  • Missing signature replay protection (replay attacks)
  • L1-L2 message failure without cancellation (locked funds)
  • Felt252算术溢出/下溢(余额操纵)
  • 缺失签名重放防护(重放攻击)
  • L1-L2消息传递失败且无取消机制(资金锁定)

Medium (Address in Audit)

中风险(审计中处理)

  • Overconstrained L1-L2 interactions (trapped funds)

  • L1-L2交互过度约束(资金被困)

8. Testing Recommendations

8. 测试建议

Unit Tests

单元测试

rust
#[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
    }
}
rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_felt252_overflow() {
        // 测试算术边界情况
    }

    #[test]
    #[should_panic]
    fn test_unauthorized_l1_handler() {
        // 错误的from_address应触发panic
    }

    #[test]
    fn test_signature_replay_protection() {
        // 相同签名使用两次应失败
    }
}

Integration Tests (with L1)

集成测试(与L1联动)

rust
// 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
}
rust
// 测试完整的L1-L2流程
#[test]
fn test_deposit_withdraw_roundtrip() {
    // 1. 在L1存入资金
    // 2. 等待L2处理
    // 3. 验证L2余额
    // 4. 提取资金到L1
    // 5. 验证L1余额恢复
}

Caracal CI Integration

Caracal CI集成

yaml
undefined
yaml
undefined

.github/workflows/security.yml

.github/workflows/security.yml

  • name: Run Caracal run: | pip install caracal caracal detect src/ --fail-on high,critical

---
  • name: Run Caracal run: | pip install caracal caracal detect src/ --fail-on high,critical

---

9. Additional Resources

9. 额外资源



10. Quick Reference Checklist

10. 快速参考检查清单

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 validate
    from_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
完成Cairo/StarkNet审计前:
算术安全(高风险):
  • 未使用felt252存储余额/金额(改用u128/u256)
  • 或felt252算术运算有明确的边界检查
  • 溢出/下溢场景已测试
L1处理函数安全(严重):
  • 所有
    #[l1_handler]
    函数都验证
    from_address
  • from_address与存储的L1合约地址对比
  • 无法通过部署替代L1合约绕过验证
L1-L2消息传递(高风险):
  • L1桥接验证地址 < STARKNET_FIELD_PRIME
  • L1桥接实现消息取消机制
  • L2处理函数检查from_address
  • L1 ↔ L2采用对称验证规则
  • 完整的往返流程已测试
签名安全(高风险):
  • 签名包含随机数(nonce)跟踪
  • 每次使用后递增随机数
  • 域分隔符包含链ID和合约地址
  • 签名重放已测试并阻止
  • 跨链重放已阻止
工具使用:
  • 已完成Caracal扫描且无严重发现
  • 单元测试覆盖所有漏洞场景
  • 集成测试验证L1-L2流程
  • 主网上线前已在测试网部署测试
undefined