mcpField
C
cairo-vulnerability-scanner

cairo-vulnerability-scanner

github.com/trailofbitsセキュリティ7.9k5.2k 回インストール今日更新
リポジトリ

cairo-vulnerability-scanner について

Cairo/StarkNetコントラクトのセキュリティレビューを支援し、算術、レイヤー間メッセージ、署名に関する6種類の脆弱性パターンを確認します。監査担当者やリリース前の評価チーム向けに、証拠と修正案を含むパターン別の結果を提示します。

主な機能

  1. 016種類のCairo/StarkNet脆弱性を確認
  2. 02L1-L2メッセージとアドレス検証を点検
  3. 03署名リプレイ対策を確認
  4. 04証拠付きのパターン別カバレッジ報告
  5. 05検出項目の修正案を提示

活用シーン

  1. 01StarkNetスマートコントラクトの監査
  2. 02L1-L2ブリッジ実装のレビュー
  3. 03リリース前の署名検証ロジック評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trailofbits/skills --skill cairo-vulnerability-scanner

インストール後、Claude Code で/cairo-vulnerability-scannerを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
assets/
trail-of-bits-mark.svg
resources/
VULNERABILITY_PATTERNS.md

詳細

Cairo/StarkNet 脆弱性スキャナー

1. 目的

StarkNet 上の Cairo スマートコントラクトを体系的にスキャンし、算術演算、クロスレイヤーメッセージング、暗号操作に関連するプラットフォーム固有のセキュリティ脆弱性を検出します。このスキルには、Cairo/StarkNet エコシステム特有の6つの重大な脆弱性パターンが含まれています。

2. このスキルを使用する場面

  • StarkNet スマートコントラクト(Cairo)の監査
  • L1-L2 ブリッジ実装のレビュー
  • StarkNet アプリケーションのローンチ前セキュリティ評価
  • クロスレイヤーメッセージ処理の検証
  • 署名検証ロジックのレビュー
  • L1 ハンドラー関数の評価

3. プラットフォームの検出

ファイル拡張子と識別子
  • Cairo ファイル:.cairo
言語/フレームワークの識別子
// 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
プロジェクト構成
  • src/contract.cairo - メインのコントラクト実装
  • src/lib.cairo - ライブラリモジュール
  • tests/ - コントラクトテスト
  • Scarb.toml - Cairo プロジェクト設定
ツールのサポート
  • Caracal:Cairo 用 Trail of Bits 静的アナライザー
  • インストール:cargo install --git https://github.com/crytic/caracal --profile release --force(Rust ツールのため、PyPI では配布されていません)
  • 使用方法:caracal detect src/
  • cairo-test:組み込みのテストフレームワーク
  • Starknet Foundry:テストおよび開発ツールキット

4. このスキルの仕組み

実行されると、次の処理を行います。

  1. コードベースを検索して Cairo ファイルを探します
  2. 各コントラクトを分析し、6つの脆弱性パターンを確認します
  3. 検出結果を報告し、ファイル参照と重大度を示します。その上に、各パターンの判定を記載したカバレッジ表を表示します
  4. 特定された各問題の修正方法を提示します
  5. メッセージングの脆弱性がないか、L1-L2 間のやり取りを確認します

5. 出力例

脆弱性が見つかった場合、次のようなレポートが表示されます。

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

6. 脆弱性パターン(6パターン)

Cairo/Starknet 特有の重大な脆弱性パターンを6つ確認します。詳細な検出パターン、コード例、緩和策、テスト戦略については、VULNERABILITY_PATTERNS.md を参照してください。

パターンの概要:
  1. Felt252 の算術オーバーフロー/アンダーフロー ⚠️ HIGH - felt252 は暗黙にラップするため、u128/u256 を使用します
  2. L1 から L2 へのアドレス変換 ⚠️ HIGH - L1 アドレスが STARKNET_FIELD_PRIME と照合して検証されていません
  3. L1 から L2 へのメッセージ失敗 ⚠️ HIGH - メッセージを消費できない場合のキャンセル経路がありません
  4. 過度に制約された L1 <-> L2 間のやり取り ⚠️ MEDIUM - 資金を動かせなくしたり、処理を妨げたりする可能性のある結合
  5. 署名のリプレイ保護 ⚠️ HIGH - ノンスがない、またはドメインセパレーターにチェーン/コントラクトが含まれていません
  6. L1 ハンドラーの未検証の from_address ⚠️ CRITICAL - あらゆる L1 コントラクトがハンドラーを実行させる可能性があります

コード例を含む脆弱性パターンの全容については、VULNERABILITY_PATTERNS.md を参照してください。

7. スキャンのワークフロー

ステップ1:プラットフォームの特定
  1. Cairo 言語と StarkNet フレームワークを確認します
  2. Cairo のバージョンを確認します(Cairo 1.0 以降か、旧 Cairo 0 か)
  3. コントラクトファイル(src/*.cairo)を特定します
  4. L1-L2 ブリッジコントラクトがあれば特定します
ステップ2:算術安全性の確認
# 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
ステップ3:L1 ハンドラーの分析

各 #[l1_handler] 関数について:

  • from_address パラメーターを検証している
  • アドレスがゼロでないことを確認している
  • 適切なアクセス制御がある
  • 監視用のイベントを発行している
ステップ4:署名検証のレビュー

署名ベースの関数について:

  • ノンスを追跡している
  • 使用後にノンスをインクリメントしている
  • ドメインセパレーターにチェーン ID とコントラクトアドレスが含まれている
  • 署名をリプレイできない
ステップ5:L1-L2 ブリッジの監査

コントラクトにブリッジ機能が含まれている場合:

  • L1 がアドレス < STARKNET_FIELD_PRIME を検証している
  • L1 がメッセージのキャンセルを実装している
  • L2 がハンドラー内の from_address を検証している
  • L1 ↔ L2 間で対称的なアクセス制御がある
  • 一連のラウンドトリップ処理をテストする
ステップ6: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

8. レポート形式

カバレッジ表

§6 のすべてのパターンについて、該当するものが見つかったかどうかにかかわらず報告します。調査結果の前にこの表を出力し、 6 行すべてを含めてください。

#パターン判定根拠
1Felt252 の算術オーバーフロー/アンダーフローclear残高は u256 です。算術処理で felt252 を検索しましたが、該当なし
2L1 から L2 へのアドレス変換
3L1 から L2 へのメッセージ失敗
4制約過多の L1 <-> L2 インタラクション
5署名のリプレイ保護
6L1 ハンドラーでの未検証の from_address

判定には次のいずれかを指定します。

  • found — file:line を示し、以下に問題の詳細をすべて記載します。
  • clear — このパターンはこのコントラクトに該当しますが、コントラクトで対処されています。読者が同じ検索を再現できるよう、検索した関数、トレイト、またはチェックを記載します。
  • n/a — このパターンはここでは該当しません。理由を 1 つの節で示します(「このコントラクトには L1 ハンドラーがない」など)。調査していないことは n/a の理由になりません。

6 行未満の表はスキャンが不完全であり、そのように報告する必要があります。Verdict のセルが空の行も同様に不完全です。上の 1 行目は形式を示すために記入済みであり、レポートを完了する前にすべての行を同じように記入してください。6 件すべてが clear という結果も、読者が対応に活用できます。2 つのパターンだけを扱い、残りの 4 つに触れないレポートは、問題のないコントラクトとまったく同じように見えます。この表はその失敗を防ぐためにあります。

問題の記載テンプレート
## [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. 優先度のガイドライン

クリティカル(即時修正が必要)
  • L1 ハンドラーでの未検証の from_address(無限発行)
  • L1-L2 アドレス変換の問題(資金がゼロアドレスに送られる)
高(デプロイ前に修正)
  • Felt252 の算術オーバーフロー/アンダーフロー(残高の操作)
  • 署名のリプレイ保護の欠如(リプレイ攻撃)
  • キャンセル機能のない L1-L2 メッセージ失敗(資金のロック)
中(監査で対処)
  • 制約過多の L1-L2 インタラクション(資金の滞留)

10. テストの推奨事項

ユニットテスト
#[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
    }
}
統合テスト(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 の統合
# .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,critical

11. 追加リソース


12. クイックリファレンスチェックリスト

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 の追跡が含まれている
  • 使用のたびに nonce をインクリメントしている
  • ドメインセパレーターにチェーン ID とコントラクトアドレスが含まれている
  • 署名のリプレイをテストし、防止している
  • クロスチェーンのリプレイを防止している

ツールの使用:

  • Caracal のスキャンが完了し、クリティカルな問題が見つかっていない
  • ユニットテストで、すべての脆弱性シナリオを網羅している
  • 統合テストで、L1-L2 フローを検証している
  • メインネットの前にテストネットへのデプロイをテスト済み
  • 6 行すべてを含むカバレッジ表を出力し、各行に理由を添えて found、clear、または n/a の判定を記載している

13. 退けるべき合理化

  • 「コントラクトは小さいので、ほとんどのパターンは明らかに該当しません。」 誰にとって明らかなのでしょうか。n/a は1つの節で済み、判断をレビュー可能にします。何も書かなければ記録は残らず、読者は確認していない場合と区別できません。
  • 「Caracal は何も報告しなかったので、コントラクトに問題はありません。」 Caracal が対象とするのはこれら6つのパターンの一部であり、ロジックレベルのパターンにはまったく対応していません。ツールの実行結果が問題なしでも、それは証拠の1行にすぎず、調査していないパターンに対する判定ではありません。どのパターンを対象にしたのかを明記してください。
  • 「このコントラクトで重要なパターンは確認しました。」 どのパターンが重要かを決めることがスキャンそのものであり、開始前の条件ではありません。行を省くのではなく、表を完成させてから重大度順に並べてください。
  • 「検出事項はなかったので、報告することはありません。」 検出事項がゼロのスキャンでも、網羅性を示す表全体を出力します。その表が成果物です。調査されたコントラクトと、ざっと目を通しただけのコントラクトを区別するためのものです。
  • 「Cairo 1 にはネイティブのオーバーフローチェックがあるので、算術は安全です。」 型を具体的に挙げてください。felt252 はサイズ付き整数型のようには動作せず、両者の境界でパターン4が発生します。
  • 「L1 側で検証しています。」 それなら L1 コントラクトを引用してください。ブリッジを介して検証されるはずだと考えているチェックは、実際に確認するまでは仮定にすぎません。未検証の from_address は、StarkNet のブリッジにおける典型的なバグです。

コメント