solidity-security について
Solidityの開発とレビュー向けに、安全規則とチェックリストをまとめたスキルです。開発者やコードレビュー担当者を対象に、コントラクトのリスク、鍵の保護、テスト要件、任意のSlither MCP分析手順を扱います。
主な機能
- 01Solidityのセキュアコーディング規則
- 02秘密鍵と環境ファイルの保護
- 03アクセス制御とリエントランシー対策
- 04監査前チェックリストとテスト要件
- 05Slither MCPの結果確認ガイド
活用シーン
- 01Solidityコントラクトの作成やレビュー
- 02トークン転送とアクセス制御の確認
- 03監査に向けたコントラクトの点検
- 04Slither MCPで構造化された検出結果を確認
MCP 対応
任意のSlither MCP連携により、検出結果、コントラクトのメタデータ、関数ソースを取得できます。未設定の場合はSlither CLIまたはチェックリストを利用します。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 0xlayerghost/ solidity-agent-kit --skill solidity-securityインストール後、Claude Code で/solidity-securityを入力して読み込まれたか確認します。
詳細
Solidity のセキュリティ基準
言語ルール
- 常にユーザーが使用している言語と同じ言語で応答してください。 ユーザーが中国語で質問した場合は、中国語で応答してください。英語の場合は、英語で応答してください。
秘密鍵の保護
- オンチェーンへの書き込みを行う前に、署名方法を開発者に選択してもらいます。
- Foundry Keystore(推奨):
cast wallet import <NAME> --interactiveでインポートし、--account <NAME>を使用します。 - 環境ファイル:
PRIVATE_KEYを.envに保存し、source .envで読み込み、"$PRIVATE_KEY"を参照します。コマンドに値をそのまま貼り付けてはいけません。
- Foundry Keystore(推奨):
- ログ、スクリーンショット、会話、コミットで秘密鍵を決して公開してはいけません。
- チームで参照できるように、プレースホルダー値を記載した
.env.exampleを用意します。 .envを.gitignoreに追加し、コミットの前に毎回git statusで確認します。- 開発者の
.envを読み取ったり、内容を表示したりしてはいけません。開発者が実行するコマンドのみを提示します。
セキュリティ判断ルール
Solidity コードを記述またはレビューする際は、以下のルールを適用します。
| 状況 | 必須の対応 |
|---|---|
| ETH/トークンの外部送金 | ReentrancyGuard と Checks-Effects-Interactions(CEI)パターンを使用します |
| ERC20 トークンとのやり取り | SafeERC20 を使用し、safeTransfer/safeTransferFrom を呼び出します。生の transfer/transferFrom は決して使用しません |
| オーナー限定関数 | OZ 4.9.x の Ownable2Step(推奨)または Ownable を継承します。Ownable2Step は誤ってオーナー権限を失うことを防ぎます |
| 複数ロールのアクセス制御 | @openzeppelin/contracts/access/AccessControl.sol の AccessControl を使用します |
| トークンの承認 | SafeERC20 の safeIncreaseAllowance/safeDecreaseAllowance を使用します。生の approve は決して使用しません |
| 価格データが必要な場合 | フィードが存在すれば Chainlink の AggregatorV3Interface を使用します。存在しない場合は、最小流動性チェックを行う TWAP を使用します。プールのスポット価格を直接使用してはいけません |
| アップグレード可能なコントラクト | TransparentProxy より UUPS(UUPSUpgradeable)を優先します。必ず Initializable を使用します |
| Solidity のバージョンが 0.8.0 未満 | SafeMath を必ず使用します。ただし、0.8.20 以降へのアップグレードを強く推奨します |
| 緊急事態 | Pausable を継承し、ユーザー向け関数に whenNotPaused を追加します。管理者/緊急時用の関数は一時停止しないでください |
| ホワイトリスト/エアドロップ | ガス効率のよい検証には MerkleProof を使用します。アドレス一覧全体をオンチェーンに保存してはいけません |
| 署名ベースの認証 | ECDSA と EIP712 を使用します。独自の署名検証を実装してはいけません |
| 署名の内容 | 署名には chainId、nonce、msg.sender、deadline を含める必要があります。リプレイとクロスチェーンでの再利用を防止します |
| クロスチェーンブリッジ/サードパーティの依存関係 | 継承するサードパーティコントラクトのコードをすべて監査します。依存関係が安全だと決めつけてはいけません |
| 非推奨/レガシーコントラクト | 非推奨のコントラクトは恒久的に pause または selfdestruct します。未使用のコントラクトをオンチェーンで呼び出し可能なままにしてはいけません |
| UUPS アップグレードパターン | _authorizeUpgrade には onlyOwner が必要です。実装コントラクトのコンストラクターで _disableInitializers() を呼び出します。upgradeTo の onlyProxy は維持します — EVMbench/basin H-01 |
| 複数コントラクト間の信頼境界 | Router/Registry の中継呼び出しでは、送信元コントラクトの認可を検証する必要があります。フラッシュローンのコールバック内で呼び出し元の識別情報を信頼してはいけません — EVMbench/noya H-08 |
| カウンター/ID と外部呼び出し | すべてのカウンターのインクリメントと ID の割り当てを外部呼び出しより前に完了させる必要があります。ETH の返金は最後に行います — EVMbench/phi H-06 |
再入可能性の保護
- 外部呼び出しを行うすべてのコントラクトで
ReentrancyGuardを継承し、nonReentrant修飾子を追加します。- インポート:
@openzeppelin/contracts/security/ReentrancyGuard.sol(OZ 4.9.x)
- インポート:
ReentrancyGuardを使用する場合でも、常に CEI パターンを適用します。- Checks(チェック) — すべての条件を検証します(
require) - Effects(状態更新) — 状態変数を更新します
- Interactions(外部とのやり取り) — 外部呼び出しを最後に行います
- Checks(チェック) — すべての条件を検証します(
入力検証
- すべてのアドレスパラメーターで
address(0)を拒否します - 資金移動ではゼロ額を拒否します
- 対応する配列を処理する際は、配列の長さが一致することを検証します
- 数値入力を妥当な範囲に制限します(ダスト攻撃やガス妨害を防止)
ガス制御
- デプロイコマンドには
--gas-limitを含めます(3,000,000 以上を推奨) forge test --gas-reportでガスを監視します — すべての PR の前に確認してくださいfoundry.tomlでオプティマイザーを設定します:optimizer = true、optimizer_runs = 200- 動的配列に対する無制限ループは避け、ページネーションまたはプルパターンを使用します
監査前チェックリスト
コードをレビューまたは監査に提出する前に、以下を確認してください。
アクセスと制御:
- すべての external/public 関数に、該当する場合は
nonReentrantが設定されている - 認証に
tx.originを使用していない(msg.senderを使用する) - 信頼できないアドレスへの
delegatecallがない - 誤って所有権を失わないよう、所有者の移転に
OwnableではなくOwnable2Stepを使用している - ユーザー向け関数を持つコントラクトが
Pausableを継承し、pause()/unpause()を備えている - UUPS の
_authorizeUpgradeにonlyOwner修飾子がある — EVMbench/basin H-01 - 実装コントラクトのコンストラクターが
_disableInitializers()を呼び出している — EVMbench/basin H-01 - Router/Registry の中継操作で、送信元コントラクトの認可を検証している — EVMbench/noya H-08
トークンと資金の安全性:
- すべての ERC20 インタラクションで
SafeERC20(safeTransfer/safeTransferFrom)を使用している - 生の
token.transfer()やrequire(token.transfer())のパターンがない - トークンの承認に生の
approveではなくsafeIncreaseAllowanceを使用している - すべての
external callの戻り値を確認している
コード品質:
- 状態変更のたびにイベントを発行している
- ハードコードされたアドレスがない — 設定またはコンストラクターパラメーターを使用する
-
.envが.gitignoreに含まれている
オラクルと価格(該当する場合):
- 価格データの取得元が Chainlink フィードまたは TWAP であり、生のスポット価格を使用していない
- オラクルに最低流動性チェックがあり、プールの準備金が少なすぎる場合はリバートする
- 価格乖離のサーキットブレーカーを備えている
テスト:
-
forge testが失敗ゼロで成功する -
forge coverageで、セキュリティ上重要なパスが十分にカバーされている - ファズテストで算術演算のエッジケース(ゼロ、最大 uint、境界値)をカバーしている
セキュリティ検証コマンド
# Run all tests with gas report
forge test --gas-report
# Fuzz testing with higher runs for critical functions
forge test --fuzz-runs 10000
# Check test coverage
forge coverage
# Dry-run deployment to verify no runtime errors
forge script script/Deploy.s.sol --fork-url $RPC_URL -vvvv
# Static analysis (if slither installed locally)
slither src/
Slither MCP 統合(利用可能な場合)
slither MCP が設定されている場合は、構造化された分析ができるため、CLI よりも優先して使用してください。
| 方法 | 使用する場面 |
|---|---|
slither src/(CLI) | ローカルで素早くスキャンする場合、生のターミナル出力 |
slither MCP get_detector_results | 影響度/確信度でフィルタリングできる構造化結果。AI が検出結果を解析して判断できます |
slither MCP get_contract_metadata | コードレビュー前にコントラクトの構造を把握する場合 |
slither MCP get_function_source | grep よりも素早く関数の実装箇所を特定する場合 |
推奨:AI エージェントを使用する場合は slither MCP を使用してください(結果が構造化され、実行可能な内容になります)。開発中の簡易的なローカルチェックには CLI を使用してください。
段階的な縮退:slither MCP と slither CLI のどちらも利用できない場合は、上記の監査前チェックリストと、カバレッジ確認のための forge test --fuzz-runs 10000 を使用してください。
コメント
Markdown 対応