第10章 セキュリティと監査#
10.0 本章の位置づけ#
本章は、本書のリファレンス実装を「公開・受託開発に耐える」状態にするためのセキュリティプロセスを示します。金融資産を扱う以上、コードが動くことと安全であることは別の要件です。本章はその後者を扱います。
本章の書き方には三つの原則を置きます。
第一に、攻撃コードそのものは掲載しません。 脆弱性は「どう攻撃するか」ではなく「どう対策し、どう検知するか」の観点で書きます。攻撃の再現可能な手順は、防御の説明に必要な最小限の記述に留めます。
第二に、脆弱性対策の対応表(10.1)は、本リポジトリの実装とテストで実際に対策・実証している項目を主軸とします。一般的なセキュリティ教本の網羅的なカタログではなく、本実装に紐づく形で書きます。本実装が構造上取り得ない攻撃面については、その旨を明示します。
第三に、未実施の工程は「未実施」と明記します。 第三者監査の委託(10.4)、Verifiable Build の実施(10.5)、バグバウンティ窓口の整備(10.6)は、本書の執筆時点では実施していません。これらの手順は公式一次情報に基づく一般的な進め方として提示し、本リポジトリで実行済みの事項(devnet E2E・CI・テスト)とは書き分けます。
なお、AI 駆動開発に伴うリスクの統制は第5章で定義済みです。本章ではそれを重複記述せず、監査観点として「統制が守られているかをどう確認するか」だけを扱います(10.3)。
10.1 典型的脆弱性と本書実装での対策対応表#
Solana プログラムの脆弱性には定番の類型があります。本節では、その各類型に対して、本リファレンス実装のどこで対策し、どのテストで実証しているかを対応させます。テスト ID は第9章のテストケース表(docs/test-cases-ch9.md)の T-* に対応します。
10.1.1 対策対応表#
| 脆弱性の類型 | 内容 | 本実装での対策(実装箇所) | 実証テスト |
|---|---|---|---|
| Missing signer check | 権限操作で署名者検証を怠り、第三者が管理操作を実行できてしまう | registry の全管理命令で admin: Signer<'info> を要求し、has_one = admin で Config の管理者と一致を検証(register_investor.rs / set_investor_status.rs / transfer_admin.rs)。Hook 側は InitializeExtraAccountMetaList で authority.is_signer を検証(transfer_hook/src/lib.rs) |
T-30 |
| 権限昇格(認可の欠落) | 管理者でない鍵が投資家状態を書き換える | 上記 has_one = admin @ RegistryError::Unauthorized。非管理者の署名では制約違反で失敗 |
T-30 |
| Account confusion(所有者検証の欠落) | 偽の、または別用途のアカウントを差し込んで検証を潜り抜ける | Hook の verify_investor_status_pda が「registry が所有していること(owner == registry::ID)」と「期待シードから導出した PDA と一致すること」の双方を検証(transfer_hook/src/lib.rs)。registry 側も set_investor_status の seeds に investor_status.investor を用いて PDA の正当性を担保 |
T-31 |
| シード取り違え(PDA の誤認) | 別投資家の正規 PDA を、未許可者の分として差し込む | Hook はトークン口座データの owner(offset 32)からシードを導出し直して照合。渡された PDA が口座 owner と対応しない場合は IncorrectAccount で失敗 |
T-32 |
| Hook バイパス(転送外呼び出し) | 転送コンテキスト外から Hook の Execute を直接呼び、検証を空回しさせる |
assert_is_transferring が送受信トークン口座の TransferHookAccount.transferring を検証。false なら ProgramCalledOutsideOfTransfer で失敗 |
T-33 |
| Hook バイパス(追加アカウント操作) | 追加アカウントを省略、または registry プログラム位置に偽物を差し込んで検証を迂回する | 追加アカウントの解決は ExtraAccountMetaList に基づき Token-2022 が行う。省略すると解決段階で失敗。registry 位置は registry_program.key != registry::ID で拒否 |
T-34 / T-35 |
| 強制権限の濫用 | Permanent Delegate 以外が強制移転を試みる | 免除は「authority がミントの PermanentDelegate 拡張値と一致する場合」に厳密に限定(authority_is_permanent_delegate)。第三者経路は送信者側 Approved 検証が働き失敗 |
T-21 |
| 算術オーバーフロー | 残高・数量計算のオーバーフローで不正な値を生む | 10.1.2 を参照(本実装は金額演算を持たず、ワークスペースで overflow-checks = true を有効化) |
— |
この表の各行は、第9章の攻撃系テスト T-30〜35 が実証になっています。つまり本実装のセキュリティ主張は、文章上の宣言ではなく、失敗を確認したテストに裏打ちされています。攻撃系テストが「防御が働いて失敗している」こと(偽陽性でないこと)は、第9章 9.5 および docs/test-cases-ch9.md 4.2 で検証済みです。失敗理由をエラーコードまで確認しています(例:T-33 は ProgramCalledOutsideOfTransfer、T-31 は IncorrectAccount)。
10.1.2 算術オーバーフローの扱い#
本リファレンス実装では、Hook プログラムも registry プログラムも、トークンの数量・残高を自前で加減算していません。 残高の増減は Token-2022 本体が行い、本実装が扱うのは「移転を許すか否か」の可否判定と、投資家状態(列挙型 Approved / Suspended)の記録のみです。したがって、本実装が直接持つ算術オーバーフローの攻撃面は限定的です。
その上で、一般的な対策としてワークスペースの Cargo.toml に overflow-checks = true を設定しています。これにより、リリースビルドでも整数演算のオーバーフローが検出されます。将来、利払い計算や数量の按分など金額演算を実装に加える場合は、チェック付き演算(checked_add 等)を用い、オーバーフロー時にエラーを返す設計にすることを推奨します。
10.2 鍵・権限の運用#
10.2.1 authority の棚卸し#
本実装が関与する権限(authority)を棚卸しし、「誰が保持すべきか」を明確にします。本書のテストでは、これらの権限を単一の payer が兼務しています。これはテストを簡略化するための構成であり、実運用では権限を分離し、マルチシグ化することを検討してください(第3章 3.1.5、第9章 9.4 の注記)。
| 権限 | 対象 | 役割 | 実運用での保持者(推奨) |
|---|---|---|---|
| mint authority | Token-2022 ミント | 新規発行(mint) | 発行体のマルチシグ |
| freeze authority | Token-2022 ミント | 口座の freeze / thaw | 発行体のマルチシグ(コンプライアンス部門の承認を要する運用) |
| permanent delegate | Token-2022 ミント | 強制移転・回収 | 発行体のマルチシグ(発動基準を社内規程化) |
| registry admin | Config PDA | 投資家の登録・状態変更 | 発行体のマルチシグ(KYC 判定と連動) |
| upgrade authority | プログラム | プログラムのアップグレード | 発行体のマルチシグ(将来的な immutable 化の判断対象) |
権限の分離は、単一の鍵が漏洩・悪用された場合の被害範囲を限定するために重要です。特に mint authority と permanent delegate は、それぞれ「発行量」と「保有者の残高」に直接影響するため、単一署名者に集約しないことを推奨します。
10.2.2 ローテーションと失効#
registry admin については、権限移管の経路を実装済みです。transfer_admin 命令が現管理者の署名(has_one = admin)を要求した上で config.admin を新しい鍵に書き換えます。これにより、鍵のローテーションや、単一鍵からマルチシグへの移行が可能です。
ミント側の authority(mint / freeze / permanent delegate)および upgrade authority のマルチシグ移管手順は、デプロイ・運用の文脈に属します。このため、具体的な移管手順は第11章 11.3 で扱います。本節では「棚卸しと分離の原則」に留めます。
10.3 AI 利用に伴うリスクの監査観点(第5章との接続)#
AI 駆動開発に伴うリスクとその統制ルールは、第5章で定義済みです。依存パッケージの実在・正当性確認、生成コードの検証規律、鍵の非共有、CI ゲート、サードパーティスキル・MCP の審査などです。本節ではこれを繰り返さず、第三者監査で「AI 利用について説明を求められた場合に、統制が守られているかをどう確認するか」という監査観点だけを列挙します。
第5章でも述べたとおり、監査で問われるのは「AI が書いたか」ではなく「どう検証したか」です。以下は、統制の遵守を確認するチェック観点です。
- 依存の正当性(第5章 5.5.2): 追加した crate / npm が公式レジストリの発行元・リポジトリで確認済みか。確認結果が記録に残っているか(本書では
docs/versions.mdと session-log に発行元 org を記録)。 - 生成コードの検証(第5章 5.5): コミットされたコードがビルド・全テスト・レビューを通っているか。無検証のコミットがないか。
- CI ゲート(第5章 5.7 / 第9章 9.7): ビルド・テスト・lint・依存監査が CI で機械的に強制されているか。人の注意力に依存していないか。
- 鍵の扱い(第5章 5.5.3): 秘密鍵・シードフレーズ・本番 RPC キーがエージェントのコンテキストやリポジトリに入っていないか。
- サードパーティ資産(第5章 5.6): 導入したスキル・MCP が公式・実績・内容確認の三点で審査されているか。
これらは、後述する第三者監査の準備物(10.4)の一部として提示できる状態にしておくことを推奨します。
10.4 第三者監査の進め方(本書リポジトリは未委託)#
本書のリファレンス実装は、執筆時点で第三者による外部監査を委託していません。 本節は、外部監査を受ける際の一般的な進め方を、公開情報に基づく観点として提示するものです。監査済みであることを主張するものではありません。
10.4.1 監査会社選定の観点#
- Solana / Anchor / Token-2022 の監査実績があること。
- 監査範囲(プログラムのみか、オフチェーン連携・鍵管理まで含むか)を事前に合意できること。
- 指摘の重大度分類と再監査(修正確認)のプロセスが明確であること。
10.4.2 監査前パッケージの準備物#
監査を効率化するため、監査会社に渡す資料を事前に整えます。本リポジトリで既に揃っているものと、追加で用意すべきものを分けて示します。
本リポジトリで既に揃っているもの:
- リポジトリ全体(プログラム・クライアント・テスト)と
README.md。 - 動作確認済みバージョン表(
docs/versions.md)。 - テストスイート(26 テスト)と、要件とのトレーサビリティ表(第3章の R- ↔ 第9章 T-)。
- CI 定義(
.github/workflows/ci.yml)と、その実機グリーンの記録(第9章 9.7)。 - 設計上の判断記録(強制回収の免除設計など。
docs/test-cases-ch9.md4.1)。
追加で用意すべきもの(監査時に整える):
- 脅威モデル(想定する攻撃者・保護対象・信頼境界)。
- 権限保持者の一覧と運用規程(10.2 の棚卸し表を、実際の保持者に置き換えたもの)。
- デプロイ対象のコミットハッシュと、検証可能ビルドのハッシュ(10.5)。
10.4.3 指摘対応プロセス#
監査の指摘は重大度(重大 / 中 / 軽微)で分類し、修正 → テスト追加 → 再監査の順で潰します。修正には必ず回帰テストを追加し、同じ脆弱性が再発しないことを CI で保証します。この「指摘を機械的ゲートに変換する」流れは、第5章・第9章の CI 統制と同じ考え方です。
10.5 Verifiable Build(solana-verify)#
10.5.1 検証可能ビルドの意義#
Verifiable Build(検証可能ビルド)は、オンチェーンにデプロイされたプログラムのバイナリが、公開されているソースコードから再現できることを検証する仕組みです。デプロイ済みプログラムのハッシュと、ソースから決定論的にビルドし直したバイナリのハッシュを比較します。公開文書として信頼性を示す上で重要な工程です。
公式ドキュメント(solana.com/docs/programs/verified-builds、確認日 2026-07-27)は、この用途に solana-verify CLI を推奨しています。配布元リポジトリは、確認日 2026-07-27 時点で solana-foundation/solana-verifiable-build(org: solana-foundation)が canonical です。従来の Ellipsis-Labs/solana-verifiable-build はこの URL へ 301 リダイレクトし、リポジトリは Solana Foundation の org へ移管済みです(ビルド・検証パイプラインの保守は引き続き Ellipsis Labs + OtterSec)。公式ドキュメントの案内 URL が旧 Ellipsis-Labs を指す場合でも、リダイレクトにより現行リポジトリへ解決されます。ビルドの決定性を担保するため、Docker が必須です(コンテナ外のビルドはシステム差で非決定的になり、検証に失敗しやすいと公式に注記されています)。
10.5.2 標準的な手順(本書リポジトリは未実施)#
本書のリファレンス実装は mainnet に未デプロイであり、検証対象となるオンチェーンプログラムが存在しないため、Verifiable Build を実施していません。 以下は公式ドキュメントに基づく標準的な流れであり、本リポジトリで実行検証したコマンドではありません(実機での実行は、mainnet デプロイ後に第11章の手順と合わせて行う想定です)。
- インストール:公式ドキュメントの案内する
cargo install solana-verify。 - 決定論的ビルド:
solana-verify build(Docker コンテナ内でビルド)。 - ローカル検証:
solana-verify verify-from-repo <repo-url> --program-id <id>(オンチェーンのハッシュとソースのハッシュを照合)。 - 検証の公開登録:
solana-verify remote submit-job(OtterSec の検証 API へ登録し、第三者が検証結果を参照できるようにする)。
具体的なフラグ・サブコマンドは版により変わり得るため、実施時に配布元(solana-foundation/solana-verifiable-build。旧 Ellipsis-Labs/solana-verifiable-build からの 301 リダイレクト先)の最新の README を一次情報として再確認してください。
10.6 バグバウンティ・脆弱性受付窓口(未整備)#
本書リポジトリは、執筆時点で脆弱性受付窓口・バグバウンティを整備していません。 公開・本番運用に向けては、以下の整備を検討してください。
- 脆弱性の受付窓口(連絡先・PGP 鍵・対応 SLA)の明示。オンチェーンプログラムには、ソース内に連絡先を埋め込む慣行(セキュリティ連絡先の記載)があります。整備する場合は、公式ドキュメントで現行の推奨形式を確認してください。
- 責任ある開示(coordinated disclosure)のポリシー。報告から公表までの手順と猶予期間を定めます。
- バグバウンティを設ける場合は、対象範囲・報奨基準・除外事項を明文化します。
これらは、10.7 のインシデント対応計画と一体で運用します。
10.7 インシデント対応計画#
10.7.1 発動できる防御手段#
本実装は、インシデント時に発動できる二つの防御手段を実装・テスト済みです。これらは「机上の計画」ではなく、実際に動作を確認した機能です。
- 凍結(freeze): 発行体は freeze authority により、特定口座を freeze して移転を止められます。KYC の失効・不正の疑いなどに用います。再 freeze で移転が止まることは第9章 T-12 で実証済みです。
- 強制回収(permanent delegate): 発行体は permanent delegate により、保有者の同意なしに残高を回収できます。裁判所命令・重大な違反時などに用います。強制回収の成立、および第三者による濫用の失敗は第9章 T-20〜23 / T-21 で実証済みです。
10.7.2 発動の判断フロー#
凍結・強制回収は投資家の権利に直接影響するため、発動には社内統制上の手続きを要します。判断フローの枠は次のとおりです(実際の基準は各社の規程・法務判断に従ってください。発動の是非や法的当否は専門家に確認してください)。
- 事象の検知(監視アラート、KYC プロバイダからの通知、当局・裁判所からの要請)。
- 事実確認と、発動権限者(マルチシグ)による承認。
- 手段の選択(移転停止で足りるなら freeze、回収が必要なら permanent delegate)。
- 実行と、監査証跡の記録(強制回収は
FORCE_TRANSFER via permanent delegateログが残ります。第7章 7.6)。 - 事後の関係者への連絡と記録の保全。
具体的な操作手順(標準作業手順書)は、第11章 11.4 の運用ランブックにまとめています。特に強制回収は「thaw → 回収 → 再 freeze」の順序を要するため、11.4.3 を参照してください。
10.7.3 コミュニケーション計画#
インシデントの内容に応じて、投資家・当局・監査法人への連絡経路と、公表の要否・タイミングをあらかじめ定めておきます。オンチェーンの操作(freeze / 強制回収)は公開台帳に記録が残るため、事後説明と齟齬のないよう、社内記録と一致させて保全します。
10.8 本章の自己チェック表#
| 観点 | 結果 |
|---|---|
| スタイル規則違反 | なし。です・ます調で統一。相互参照は番号(第3/5/7/9/11章、9.4/9.5/9.7/11.3/11.4)。マーケティング語彙・価格/投資リターン言及なし。法的当否は「専門家に確認」で統一(10.7.2) |
| 攻撃コードの不掲載 | 攻撃コードは掲載していない。脆弱性は「対策と検知」の観点で記述し、実証は第9章のテスト ID(T-*)への参照で示した(設計書3.4 第10章の注意) |
[要検証] の残数 |
0件。未実施の工程(第三者監査=10.4 / Verifiable Build=10.5 / バグバウンティ=10.6)は本文で「未実施」と明記し、手順は一次情報に基づく一般的な進め方として提示(タグは残さない方針) |
| 実装・テストとの対応 | 対策対応表(10.1)は本リポジトリの実装(transfer_hook/src/lib.rs・registry の各命令・Cargo.toml の overflow-checks)と第9章テスト(T-21, T-30〜35)に紐づけ済み |
| 第5章との重複回避 | AI 統制(10.3)は第5章を参照し、監査観点のチェックリストのみに留めた。重複記述なし |
| バージョン表との不一致 | なし(本章はバージョン依存の固定コマンドを本文で断定していない。solana-verify のコマンドは版により変わり得る旨を明記) |
| 一次情報の帰属確認 | solana-verify=solana-foundation/solana-verifiable-build(canonical。旧 Ellipsis-Labs/… は 301 リダイレクト=移管済み。確認日 2026-07-27。保守は Ellipsis Labs + OtterSec)。マルチシグの詳細(Squads の帰属)は第11章 11.3 で確認・明記 |