solidity-audit について
Solidityコントラクトの監査やコードレビュー向けのセキュリティチェックリストです。一般的な脆弱性に加え、プロキシ、信頼境界、状態更新順序に関する確認項目も扱います。
主な機能
- 01再入とアクセス制御の確認
- 02入力、オラクル、数値リスクの確認
- 03署名、ERC20、フロントランの確認
- 04プロキシ更新とコントラクト間の信頼確認
- 05状態順序とアドレス単位の制限回避の確認
活用シーン
- 01Solidityコントラクトの脆弱性監査
- 02プロキシ更新権限のレビュー
- 03コントラクト間呼び出しと状態依存の分析
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 0xlayerghost/ solidity-agent-kit --skill solidity-auditインストール後、Claude Code で/solidity-auditを入力して読み込まれたか確認します。
詳細
Solidity セキュリティ監査チェックリスト
言語ルール
- 必ず、ユーザーが使用している言語で応答してください。 ユーザーが中国語で質問した場合は中国語で、英語で質問した場合は英語で応答してください。
使用方法:このスキルはセキュリティ監査とコードレビュー用です。自動的には呼び出されません。コントラクトの脆弱性を確認する際は
/solidity-auditを呼び出してください。
コントラクトレベルの脆弱性
1. 再入可能性
| 種類 | 説明 | 確認項目 |
|---|---|---|
| 同一関数 | 攻撃者がフォールバック/receiveを介して同じ関数に再入する | すべての外部呼び出しが状態更新後に行われているか(CEIパターン)? |
| 関数間 | 攻撃者が共有状態を扱う別の関数に再入する | 共有状態にアクセスするすべての関数が nonReentrant で保護されているか? |
| コントラクト間 | 攻撃者が古い状態を読み取る別のコントラクトを介して再入する | 外部コントラクトが中間状態を読み取れないようになっているか? |
| 読み取り専用 | 実行途中の状態で、View関数が古いデータを返す | 状態遷移中に、重要なView関数がオラクルとして使われていないか? |
事例:GMX v1(2025年7月、4,200万ドル) — Arbitrum上のGLPプールで再入可能性が発生し、攻撃者が出金を繰り返して流動性を枯渇させました。
2. アクセス制御
| 確認項目 | 詳細 |
|---|---|
| 修飾子の欠落 | 状態を変更するすべての関数に、明示的なアクセス制御が設定されているか? |
| 修飾子のロジック | 修飾子は失敗時に実際にリバートするか(単に空のチェックを行うだけではないか)? |
| 状態フラグ | 一度だけアクセス可能なパターンでは、ユーザーごとにストレージが適切に更新されているか? |
| 管理者権限の範囲 | オーナー権限は最小限で、期限が設定されているか? |
事例:Bybit(2025年2月、14億ドル) — Safe{Wallet}のUIに悪意のあるJSが注入され、署名プロセスが乗っ取られました。コントラクトの欠陥ではありませんが、インフラ層のアクセス制御に関する事例です。
3. 入力検証
| 確認項目 | 詳細 |
|---|---|
| ゼロアドレス | すべてのアドレス引数で address(0) を拒否しているか? |
| ゼロ額 | 資金の送金でゼロ額を拒否しているか? |
| 配列の境界 | 対応する配列の長さが一致することを検証しているか? |
| 任意の呼び出し | 攻撃者が data を制御できる、検証されていない address.call(data) がないか? |
| 数値の範囲 | ダスト攻撃やガスの妨害を防ぐため、入力値に上限・下限を設けているか? |
4. フラッシュローン攻撃
| 種類 | 仕組み | 防御策 |
|---|---|---|
| 価格操作 | フラッシュローンで借入 → スワップして価格を変動 → 価格依存のロジックを悪用 → 返済 | 最低流動性チェック付きのTWAPオラクル |
| ガバナンス | ガバナンストークンをフラッシュローンで借入 → 投票 → 同一ブロック内に返済 | スナップショット投票+最低保有期間+48時間以上のタイムロック |
| 清算 | フラッシュローンで借入 → 担保価値を操作 → 清算を実行 | 複数のオラクルによる価格検証+サーキットブレーカー |
| 複合(丸め誤差) | フラッシュローンで借入 → プールを操作 → 微小な出金で丸め誤差を悪用 → 返済 | 最低出金額+仮想シェア |
事例:
- Cream Finance(2021年10月、1億3,000万ドル) — フラッシュローン+yUSDオラクル操作+再入可能性ガードの欠落
- Abracadabra(2025年3月、1,300万ドル) — cauldronの状態追跡エラー、自己清算+不良債権
- Bunni(2025年9月、840万ドル) — フラッシュローン+プール価格操作+丸め誤差を悪用した微小な出金
5. オラクルと価格
| 確認項目 | 詳細 |
|---|---|
| 単一のオラクルへの依存 | 独立した価格ソースを複数使用していますか? |
| 価格の古さ | updatedAt のタイムスタンプを確認し、古いデータを拒否していますか? |
| スポット価格の使用 | 価格算出に AMM の生のリザーブを使用していませんか? |
| 最低流動性 | プールのリザーブがしきい値を下回った場合、オラクルはリバートしますか? |
| 価格の乖離 | 価格が最後に確認された値からしきい値を超えて変動した場合、サーキットブレーカーが作動しますか? |
| Chainlink ラウンドの完全性 | answeredInRound >= roundId を確認していますか? |
事例:Cream Finance(2021 年 10 月、1 億 3,000 万ドル) — 攻撃者は供給量を減らして yUSD ボールトの価格を操作し、価格が水増しされた担保を使ってすべてのレンディングプールから資金を流出させました。
6. 数値に関する問題
| 種類 | 説明 | 防御策 |
|---|---|---|
| プリミティブ型のオーバーフロー | uint256 a = uint8(b) + 1 — Solidity ≥0.8 では b=255 の場合にリバートします | 型を一貫させ、暗黙的な縮小変換を避けます |
| 切り詰め | int8(int256Value) — ≥0.8 でも警告なしにオーバーフローします | 型を縮小する際は、すべて SafeCast ライブラリを使用します |
| 丸め/精度の損失 | usdcAmount / 1e12 は少額の場合、常に 0 に丸められます | 乗算してから除算し、結果がゼロでないか確認します |
| 乗算前の除算 | (a / b) * c は精度を失います | 常に (a * c) / b とします |
事例:Bunni(2025 年 9 月、840 万ドル) — 少額の出金における丸め誤差が、フラッシュローンを通じて悪用されました。
7. 署名に関する問題
| 種類 | 説明 | 防御策 |
|---|---|---|
| ecrecover が address(0) を返す | 無効な署名に対して、リバートせず address(0) を返します | 常に recovered != address(0) を確認します |
| リプレイ攻撃 | 同じ署名が複数のトランザクション/チェーンで再利用されます | 署名対象データに chainId + nonce + deadline を含めます |
| 署名の可鍛性 | ECDSA では、署名ごとに有効な (s, v) の組み合わせが 2 つあります | OpenZeppelin の ECDSA.recover を使用します(low-s を強制します) |
| 空ループによる回避 | for ループ内で署名を検証する場合、攻撃者が空の配列を送信します | ループの前に signatures.length >= requiredCount を確認します |
| msg.sender との紐付け漏れ | 証明/署名が呼び出し元に紐付けられていません | 署名/証明対象データには必ず msg.sender を含めます |
8. ERC20 互換性
| 問題 | 説明 | 防御策 |
|---|---|---|
| 送金手数料 | transfer(100) で実際に届くトークンが 100 未満の場合があります | 送金前後の残高を確認し、実際の受取額を使用します |
| リベーストークン | 送金なしでトークン残高が変化します | 外部残高をキャッシュせず、常に最新の値を読み取ります |
| bool を返さない | 一部のトークン(USDT)は、transfer 時に bool を返しません | SafeERC20.safeTransfer を使用します |
| ERC777 フック | 送金フックによって再入が発生する可能性があります | トークンを受け取るすべての関数で ReentrancyGuard を使用します |
| ゼロ額の送金 | transferFrom(A, B, 0) — アドレスポイズニング | ゼロ額の送金を拒否します |
| 承認の競合 | allowance を N から M に変更すると、N+M が使用可能になります | safeIncreaseAllowance / safeDecreaseAllowance を使用します |
9. MEV/フロントランニング
| 種類 | 説明 | 防御策 |
|---|---|---|
| サンドイッチ攻撃 | 攻撃者が被害者の取引を挟むように、買いを先行し、売りを後続させます | スリッページ保護 + deadline パラメーター |
| ERC4626 インフレーション | 最初の預け入れ者が寄付をしてシェア価格を水増しし、後続の預け入れ者に丸め誤差を生じさせます | 最低初回預け入れ額を設けるか、仮想シェアを使用します(offset 付きの ERC4626) |
| 承認のフロントラン | 新しい allowance のトランザクションが確定する前に、攻撃者が古い allowance を使います | approve ではなく increaseAllowance を使用します |
| 制限のない出金 | 攻撃者が出金トランザクションをメンプールで監視し、自分の取引を先行させます | コミット・リビール方式、または認証との紐付けを必須にします |
10. ストレージと低レベル操作
| 問題 | 説明 |
|---|---|
| ストレージポインター | Foo storage foo = arr[0]; foo = arr[1]; — arr[0] は更新されません |
| ネストされた削除 | delete structWithMapping — 内部のマッピングデータは残ります |
| プライベート変数 | eth_getStorageAt を使えば、コントラクトのストレージはすべて公開で読み取れます |
| 安全でない delegatecall | 信頼できないコントラクトへの delegatecall により、呼び出し元が selfdestruct される可能性があります |
| プロキシのストレージ衝突 | アップグレードで親コントラクトの順序が変わると、変数同士が上書きされます(ストレージギャップを使用してください) |
| ループ内の msg.value | ループ内で msg.value は減少しないため、二重支出が可能になります |
11. コントラクト検出の回避
| 手法 | 仕組み |
|---|---|
| コンストラクター呼び出し | コンストラクターから攻撃します。デプロイ中は extcodesize == 0 です |
| CREATE2 による事前計算 | コントラクトアドレスを事前計算し、デプロイ前に EOA として使用します |
12. プロキシとアップグレードの脆弱性
出典:EVMbench Paper §4.2, Appendix H / Code4rena 2024-07-basin H-01
| チェック項目 | 詳細 |
|---|---|
_authorizeUpgrade のアクセス制御 | UUPS の _authorizeUpgrade に onlyOwner 修飾子が必要ですか? |
| パーミッションレスなファクトリー/レジストリー | 攻撃者はパーミッションレスなファクトリー(例:Aquifer の boreWell)を使って、アップグレードチェックを満たせますか? |
upgradeTo の修飾子 | オーバーライドされた upgradeTo/upgradeToAndCall に onlyProxy 修飾子が引き継がれていますか? |
| イニシャライザーの保護 | initializer 修飾子によって再初期化が防止されていますか? 実装で _disableInitializers() を呼び出していますか? |
| ストレージレイアウトの互換性 | ストレージギャップや ERC-7201 名前空間など、アップグレードに安全なストレージレイアウトですか? |
事例:Code4rena 2024-07-basin H-01(EVMbench Paper Fig.12, p.19 による)— _authorizeUpgrade は delegatecall と Aquifer への登録のみをチェックし、onlyOwner がありませんでした。そのため、誰でも Well プロキシを悪意のある実装にアップグレードして資金を流出させることができました。Oracle の修正では、onlyOwner 修飾子を1つ追加しています。
13. 信頼境界とプロトコルのコンポーザビリティ
出典:EVMbench Paper §4.2.1, Fig.6 / Code4rena 2024-04-noya H-08、2024-07-benddao
| チェック項目 | 詳細 |
|---|---|
| ボールト間の信頼分離 | レジストリー/ルーターの中継呼び出しで、ボールトレベルの認可を検証していますか? |
| 信頼済み送信元の悪用 | sendTokensToTrustedAddress のような関数は、ルーターの識別情報だけでなく、送信元のボールトも検証していますか? |
| フラッシュローンとルーティングの組み合わせ | 攻撃者はフラッシュローンのコールバックを利用して、ルーターになりすまし、任意のボールトを偽装できますか? |
| 担保の所有権検証 | 清算/ステーキング操作で、NFT/担保の実際の所有者を検証していますか? |
| コントラクト間の状態依存性 | 複数のコントラクト間のやり取りに、中間状態への依存がありませんか? |
事例:
- Code4rena 2024-04-noya H-08(EVMbench Paper §4.2.1, Fig.6, p.8-9 による)— PositionRegistry と BalancerFlashLoan の処理経路にボールトレベルの認証がありませんでした。キーパーはフラッシュローンを使ってルーターに任意のボールトを偽装させ、
sendTokensToTrustedAddress経由でボールト間の資金を流出させました - Code4rena 2024-07-benddao(EVMbench Paper Fig.13, p.19 による)—
isolateLiquidateは NFT の所有権を検証していなかったため、攻撃者は他者の tokenId を指定して清算を実行できました
14. 状態の順序とカウンター操作
出典:EVMbench Paper Appendix H.1, Fig.19-21 / Code4rena 2024-08-phi H-06
| チェック項目 | 詳細 |
|---|---|
| カウンター/ID のインクリメント順序 | credIdCounter++ などの ID のインクリメントは、外部呼び出しの前に行われますか? |
| 作成時の自動購入 | 自動的に buy() を呼び出す create() 関数は、ID/状態が完全に初期化された後にのみ実行されますか? |
| 返金のタイミング | ETH の返金(超過分)は、すべての状態更新の完了後に行われますか? |
| ボンディングカーブのメタデータ上書き | 攻撃者が再入してボンディングカーブ/価格設定パラメーターを変更できますか?(安く購入し、高価なカーブに切り替えて、高く売却できますか?) |
事例:Code4rena 2024-08-phi H-06(EVMbench Paper Appendix H.1, p.25-28 経由)— _createCredInternal は credIdCounter をインクリメントする前に buyShareCred を呼び出していました。_handleTrade は lastTradeTimestamp を更新する前に超過 ETH を返金していました。攻撃者は再入して安価なカーブでシェアを蓄積し、メタデータを高価なカーブに上書きしてから、売却してコントラクトの ETH をすべて引き出しました。修正方法:buyShareCred/sellShareCred に nonReentrant を追加します。
15. アドレス単位の状態制限の回避
mapping(address => ...)に基づく制限は、複数のアドレスへの分散や中間転送によって回避できる可能性があります。
| 制限の種類 | 回避方法 | 防御策 |
|---|---|---|
クールダウン(_lastTxTime[addr]) | A が購入 → B に転送 → B が即座に売却 | 転送時に送信者のクールダウンを引き継ぐ:_lastTxTime[to] = _lastTxTime[from] |
最大トランザクション量(maxTxAmount) | N 個のアドレスに分散し、それぞれを上限内に収める | tx.origin によるブロックごとの制限も設けるか、既知のトレードオフとして受け入れる |
最大ウォレット残高(maxWalletBalance) | 同じ主体が管理する複数のウォレットにトークンを分配する | オンチェーンでの強制は本質的に難しいため、オフチェーンで監視する |
同一ブロック内の保護(_lastTxBlock[addr]) | 同じブロック内で別のアドレスを使う | 送信元のブロックを引き継ぐ:_lastTxBlock[to] = _lastTxBlock[from] |
| 取引回数の上限 | アドレスを切り替え、それぞれで 1 回ずつ取引する | クールダウンと同様に、転送時に状態を引き継ぐ |
監査手法(3 ステップ):
- アドレス単位の状態をすべて特定する:
mapping(address =>を検索し、それぞれについて「アドレスを切り替えることで回避できるか?」を確認します。 - すべてのトークンフロー経路を追跡する:トークンが移動するすべての経路(購入、売却、転送、ミント)をマッピングします。各経路で制限状態が更新されるかを確認します。最も見落とされやすいのは、ウォレット間の転送経路です。
- 状態の推移を確認する:A が制限状態を持ち、トークンを B に転送した場合、B はその状態を引き継ぎますか? 引き継がない場合、回避可能な脆弱性があります。
防御の原則:トークンフローには制限状態を伴わせます。トークンが移動する先には、関連するアドレス単位の状態も引き継がれる必要があります。
よくある落とし穴 2 つ:
block.timestampを利用したグリーフィング:_lastTxTime[to] = block.timestampを使用すると、誰でも対象にダストトークンを送ってクールダウンをリセットし、グリーフィングできます。代わりに送信者の状態を使用します。- 直接代入による上書き:
_lastTxTime[to] = _lastTxTime[from]を使用すると、クールダウンがほぼ終了した送信者によって受信者の既存のクールダウンが短縮される可能性があります。maxを使用します:if (_lastTxTime[from] > _lastTxTime[to]) _lastTxTime[to] = _lastTxTime[from]— 延長のみを行い、短縮はしません。
インフラレベルの脆弱性
16. フロントエンド/UI インジェクション
攻撃者は dApp のフロントエンドまたは署名インターフェースに悪意のあるコードを注入します。
防御策:署名前に、トランザクションの calldata が想定された関数セレクターおよびパラメーターと一致することを確認します。デバイス上でトランザクションをプレビューできるハードウェアウォレットを使用します。フロントエンドの依存関係を定期的に監査します。
事例:Bybit(2025 年 2 月、14 億ドル) — 悪意のある JavaScript が Safe{Wallet} の UI に注入され、署名中にトランザクションデータが改ざんされました。
17. 秘密鍵とソーシャルエンジニアリング
2025~2026年も、秘密鍵の漏えいが損失の最大の原因です。
防御策:秘密鍵は HSM またはハードウェアウォレットに保管します。すべてのトレジャリー操作と管理操作でマルチシグ(3/5 以上)を使用します。「サポート」担当者にシードフレーズを共有しないでください。ソーシャルエンジニアリングに関する意識向上トレーニングを定期的に実施します。
事例:Step Finance(2026年1月、3,000万ドル) — デバイスへの侵害を通じて、トレジャリーウォレットの秘密鍵が漏えいしました。
18. クロスチェーンブリッジ
| 確認項目 | 詳細 |
|---|---|
| 継承したコード | サードパーティ製フレームワークから継承したブリッジのロジックをすべて監査します |
| メッセージの検証 | クロスチェーンメッセージは、適切な署名とリプレイ攻撃対策によって検証されていますか? |
| 流動性の分離 | ブリッジ資金はプロトコルのトレジャリーと分離されていますか? |
事例:SagaEVM(2026年1月、700万ドル) — Ethermint から脆弱な EVM プリコンパイル済みブリッジのロジックを継承していました。
19. レガシー/非推奨のコントラクト
既知のバグがある古いコントラクトは、オンチェーン上で永久に呼び出し可能なままです。
防御策:非推奨のコントラクトを恒久的に pause するか、そこから資金を移行します。古いコントラクトアドレスで予期しないアクティビティがないか監視します。非推奨にする前に、ミント機能と管理者機能を削除します。
事例:Truebit(2026年1月、2,640万ドル) — Solidity 0.6.10 のコントラクトにオーバーフロー保護がなく、攻撃者はほぼゼロのコストでトークンをミントしました。
Slither MCP による自動分析(利用可能な場合)
slither MCP が設定されている場合は、以下の手動チェックリストを実施する前に、自動分析を実行します。
推奨する監査フロー
Step 1: slither MCP automated scan
→ get_detector_results(path, impact="High")
→ get_detector_results(path, impact="Medium")
Step 2: Review Slither findings — triage true positives vs false positives
Step 3: Manual checklist below — catch what Slither misses (business logic, economic attacks)
Step 4: Cross-reference — Slither + manual findings combined into final report
Slither MCP ツール
| ツール | 用途 | 補完する項目 |
|---|---|---|
get_contract_metadata | 関数、継承関係、フラグを抽出します | 手動によるアクセス制御のレビュー |
get_function_source | 行番号付きの正確なソースコードを取得します | コードの検索を grep より迅速化 |
find_implementations | 関数シグネチャのすべての実装を検索します | コントラクト間のリエントランシー分析 |
get_detector_results | 90 種類以上のセキュリティ検出器を実行し、影響度/確信度でフィルタリングします | 手動チェックリストの自動化版 |
get_detector_metadata | 説明付きで利用可能な検出器を一覧表示します | チェック対象の把握 |
Slither が検出できる問題と検出できない問題
| Slither が得意とする検出 | 引き続き必要な手動レビュー |
|---|---|
| リエントランシーのパターン | ビジネスロジックの欠陥 |
| 保護されていない関数 | 経済的な攻撃ベクトル(フラッシュローンの組み合わせ) |
| 未使用の状態変数 | プロトコル間のコンポーザビリティリスク |
| シャドーイングの問題 | オラクル操作のシナリオ |
| ERC20 インターフェースの誤り | 信頼境界のアーキテクチャ上の問題 |
| デッドコード | ビジネスロジック固有の MEV/フロントランニング |
重要な原則:Slither は静的解析によって確かな事実を提供し、既知の脆弱性パターンに対する偽陰性を減らします。ただし、プロトコルレベルの経済的な攻撃を推論することはできません。そのため、以下の手動チェックリストが不可欠です。
適切な縮退動作:slither MCP が設定されていない場合は、このセクションをスキップし、手動チェックリストに直接進みます。チェックリストの項目はすべて、そのまま有効に使用できます。
監査実施チェックリスト
セキュリティ監査を実施する際は、各項目を確認してください。
リエントランシー:
- 外部呼び出しを行うすべての関数で
nonReentrantを使用している - CEI パターンに従っている — 外部呼び出し後に状態を読み取っていない
- 状態遷移中にビュー関数をオラクルとして使用していない
アクセス制御:
- 状態を変更するすべての関数に明示的なアクセス修飾子がある
- 修飾子が実際にリバートする(黙って処理を通さない)
- 管理者権限が最小限で、文書化されている
入力とロジック:
- 検証されていない任意の
call/delegatecallがない - 認証に
tx.originを使用していない - 対応する入力の配列長を検証している
- 乗算前の除算による精度損失がない
トークンの取り扱い:
- すべての ERC20 操作で
SafeERC20を使用している - 手数料徴収型トークンに対応している(残高差分を確認)
- リベーストークンの残高をキャッシュしていない
- ゼロ額の送金を拒否している
価格とオラクル:
- 生のスポット価格を使用していない
- 価格の古さを確認している(
updatedAt/answeredInRound) - 最低流動性しきい値を適用している
- 価格乖離のサーキットブレーカーがある
署名と暗号技術:
-
ecrecoverの結果がaddress(0)ではないことを確認している - 署名データに
chainId、nonce、msg.sender、deadlineが含まれている - OZ の
ECDSAを使用している(low-s を適用) - MerkleProof のリーフが
msg.senderに紐付いている
フラッシュローン対策:
- ガバナンス:スナップショット投票+保有期間+タイムロック
- 価格:単一ブロックのスポット価格ではなく、TWAP または複数のオラクルを使用
- ボールト:初回入金額の最低値または仮想シェアを設定(ERC4626)
プロキシとアップグレード(EVMbench:
- UUPS の
_authorizeUpgradeにonlyOwnerがある — [EVMbench/basin H-01] -
upgradeTo/upgradeToAndCallにonlyProxyが維持されている — [EVMbench/basin H-01] - 実装のコンストラクターで
_disableInitializers()を呼び出している — [EVMbench/basin H-01] - ストレージレイアウトがアップグレードと互換性がある(ストレージギャップまたは ERC-7201)— [EVMbench/basin H-01]
信頼境界とコンポーザビリティ(EVMbench:
- ルーター/レジストリの中継呼び出しで、呼び出し元が許可されたボールト/コントラクトであることを確認している — [EVMbench/noya H-08]
- 清算処理で、担保の実際の所有権を確認している — [EVMbench/benddao]
- フラッシュローンのコールバック経路を悪用して信頼境界を突破できない — [EVMbench/noya H-08]
- 複数コントラクト間のやり取りで、中間状態に依存していない — [EVMbench/noya H-08]
状態の順序付け(EVMbench:
- 外部呼び出しの前にカウンター/ID のインクリメントを完了している — [EVMbench/phi H-06]
- ETH の返金をすべての状態更新の後に実行している — [EVMbench/phi H-06]
- 作成関数内の自動処理(自動購入など)を完全な初期化の後に実行している — [EVMbench/phi H-06]
アドレスごとの状態の迂回:
- すべての
mapping(address => ...)の制限について、複数アドレスによる迂回がないか監査している - ウォレット間の送金経路で、関連する制限状態が伝播する
- 状態の伝播に
max(_lastTxTime[to], _lastTxTime[from])を使用している —block.timestamp(嫌がらせ攻撃)や直接代入(上書きによる期間短縮)ではない
インフラストラクチャ:
- サードパーティの依存関係を監査している(ブリッジコード、継承したコントラクト)
- 管理者/ミント関数を呼び出せる非推奨コントラクトが残っていない
- すべてのトレジャリーおよび管理者ウォレットでマルチシグを使用している
- フロントエンドでトランザクションを検証している(calldata が想定どおりであること)
AI エージェントの監査手法
出典:EVMbench (OpenAI/Paradigm, Feb 2026) — Detect/Patch/Exploit モードで、Code4rena の40件の監査リポジトリから抽出した重大度の高い脆弱性120件を対象に、AI エージェントを評価しました。
監査戦略
- 深さより網羅性:対象範囲内のファイルをすべてスキャンし、最初の脆弱性を見つけた時点で止めないでください [EVMbench §5, p.10]
- 3段階の監査:検出(脆弱性を特定)-> パッチ(修正を記述)-> エクスプロイト(PoC を構築) [EVMbench §3.2, p.5]
- 段階的な出力:進捗を保つため、監査中に継続して検出結果を記録してください [EVMbench Appendix G, Fig.18, p.24]
- 体系的なカテゴリ別スキャン:直感に頼るのではなく、脆弱性の種類(再入可能性、アクセス制御、数値処理、オラクルなど)ごとに確認してください [EVMbench §3.1, p.4]
- 修正の検証:パッチ適用後、元のテストが引き続きすべて成功すること、かつエクスプロイトがもはや成立しないことを確認してください [EVMbench §3.2.2, p.5]
高頻度の脆弱性パターン(Code4rena のデータ)
出典:EVMbench Table 4(p.17)— 監査リポジトリ40件
- アクセス制御の欠如(アップグレード機能、清算、管理者機能) — basin H-01, munchables, benddao
- 再入可能性 + 状態の順序に関するエラー(状態更新前の返金) — phi H-06, noya H-08
- フラッシュローンによる信頼境界の侵害(ルーター/レジストリ間の信頼伝播を悪用) — noya H-08
- 署名のリプレイ/フロントランニング(チェックポイントの回避、セッション署名のリプレイ) — sequence H-01, H-02
- 数値精度/丸め処理(ボンディングカーブ、少額の引き出し) — abracadabra H-02, size H-02
主な調査結果
出典:EVMbench Paper §4.1(p.7)、Fig.7(p.10)、Fig.10(p.18)、Fig.11(p.19)
- メカニズムのヒントがあると、パッチの成功率は約40%から約94%に上昇します [Fig.7] — エージェントは修正方法を把握しているものの、脆弱性の発見に苦労しています
- ほとんどの脆弱性は、修正に必要なコードが5行以下です [Fig.10, p.18]
- ほとんどのエクスプロイトに必要なトランザクションは1~3回のみです [Fig.11, p.19]
- 検出数が実際の脆弱性数に最も近いエージェントが最高得点を獲得します(量より質) [Fig.5, p.8]
2021-2026年のインシデント早見表
| 日付 | プロジェクト | 損失額 | 攻撃の種類 | 根本原因 | 出典 |
|---|---|---|---|---|---|
| 2021年10月 | Cream Finance | $130M | フラッシュローン + オラクル | 供給量の減少を利用した yUSD ボールト価格の操作 | rekt.news |
| 2025年2月 | Bybit | $1.4B | UI インジェクション/サプライチェーン | 開発者のマシンが侵害され、Safe{Wallet} の JS が改ざんされた | NCC Group |
| 2025年3月 | Abracadabra | $13M | ロジックの欠陥 | cauldron の清算における状態追跡エラー | Halborn |
| 2025年7月 | GMX v1 | $42M | 再入可能性 | Arbitrum 上の GLP プールにおけるコントラクト間の再入可能性 | Halborn |
| 2025年9月 | Bunni | $8.4M | フラッシュローン + 丸め処理 | 引き出し時の丸め方向の誤り、44回の少額引き出し | The Block |
| 2025年10月 | Abracadabra #2 | $1.8M | ロジックの欠陥 | cook() の検証フラグがリセットされ、担保なしで MIM が借り入れられた | Halborn |
| 2026年1月 | Step Finance | $30M | キーの侵害 | デバイス侵害により、トレジャリーウォレットの秘密鍵が盗まれた | Halborn |
| 2026年1月 | Truebit | $26.4M | レガシーコントラクト | Solidity 0.6.10 の整数オーバーフローによるミント価格の算出 | CoinDesk |
| 2026年1月 | SagaEVM | $7M | サプライチェーン/ブリッジ | 継承された Ethermint のプリコンパイル済みブリッジの脆弱性 | The Block |