Security
Kova は、AI エージェントが暗号資産を安全に扱えるよう、複数のセキュリティ層を提供しています。鍵管理 / OperationKind 分類 / Signer 抽象化 / fail-closed な spending_limit を組み合わせて、誤送金や不正利用を防いでいます。
現行仕様: 本ページは OperationKind 分類 / Signer 抽象化 / spending_limit を中心とした構成を解説します。旧
KOVA_MODEenv /config.jsonmodefield による mode 検知設計はすべて廃止されています。
鍵管理
ローカル保存と暗号化
Kova の秘密鍵は、ローカルマシンに暗号化されて保存されます:
保存場所: ~/.kova/wallets/<wallet-id>.json
暗号化仕様:
- アルゴリズム: AES-256-GCM(Galois/Counter Mode)
- 鍵派生: PBKDF2(Password-Based Key Derivation Function 2)
- イテレーション: 100,000 回
- ソルト: ランダム生成(16 バイト)
- 認証タグ: 改ざん検出(16 バイト)
秘密鍵は 決して平文で保存されません。ファイルの内容は以下のような形式です:
{
"version": 1,
"id": "68cf6dba-e5f1-4c3a-9b2e-1234567890ab",
"name": "my-wallet",
"encrypted": "...",
"salt": "...",
"iv": "..."
}パスフレーズの重要性
ウォレットの安全性は、パスフレーズの強度に依存します。強力なパスフレーズを設定してください:
推奨:
- 12 文字以上
- 大文字・小文字・数字・記号を含む
- 辞書に存在する単語を使わない
- 他のサービスと使い回さない
悪い例: password123 / mywalletpass / Agent2024!
良い例: Xk9$mP2#vQ8@wL5& / T7rZ!pN3*dF6@hB9^
ファイルパーミッション
ウォレットファイルのアクセス権限を制限することで、他のユーザーからの読み取りを防ぎます:
# ウォレットディレクトリのパーミッション設定
chmod 700 ~/.kova/wallets
# ウォレットファイルのパーミッション設定
chmod 600 ~/.kova/wallets/*.jsonOperationKind 3 分類
Kova は mode を検知する 設計を採用しません。代わりに、すべてのコマンドを OperationKind で 3 分類し、実行 context(TTY 有無)と認証手段(passphrase / OWS API key)の組み合わせで経路が自動決定されます。
| OperationKind | 副作用 | 認証 | agent から(非 TTY) | terminal から(TTY) | 代表コマンド |
|---|---|---|---|---|---|
read-only | なし | 不要 | ✅ そのまま | ✅ そのまま | balance / wallet info / policy list / key list / status |
policy-gated | あり(チェーン書込) | passphrase または API key | ✅ OWS API key で server に依頼 → policy で gate | ✅ passphrase 入力でローカル署名 | send / call / sign サブコマンド / delegate create / revoke |
owner-only | あり(local state / 鍵生成 / policy 更新) | passphrase 必須 | ❌ block (INTERACTIVE_INPUT_REQUIRED) | ✅ passphrase + readline 確認 | wallet export/reset-passphrase / policy create/remove/update / key rotate / init / skills install/remove/update / plugin install/uninstall / config set |
fail-closed default: 上記いずれにも分類されない操作は owner-only として扱われます。CLI 入口のガードが要件を強制し、agent モードからの owner-only 操作呼び出しは構造的に拒否されます。
補足: 旧
KOVA_MODE/config.jsonのmodefield、および「mode を見て分岐する」コードはすべて削除されています。config set credential ''のみ「agent → owner 復帰」経路として guard より前で処理する例外として保持されます。
詳細リファレンス: Reference: OperationKind 分類 で各分類のコマンド一覧と guard 実装を参照できます。
--owner フラグの意味
--owner flag は passphrase 署名を強制する flag です。credential (OWS API key) が config に設定されていても本 flag を指定すると API key を無視し、ローカル passphrase 署名経路 (PassphraseSigner) を選択します。policy-gated 操作(send / call / sign / delegate 等)で利用します。
| context | --owner 指定 | 経路 |
|---|---|---|
| TTY あり | あり | passphrase 経路(PassphraseSigner) |
| TTY あり | なし | passphrase 経路(TTY フォールバック) |
| 非 TTY | あり | エラー(passphrase 入力できない) |
| 非 TTY | なし(credential あり) | API key 経路(ApiKeySigner) |
本番環境で AI エージェントに使わせる場合は、--owner を使わずに API key + policy 経路(policy-gated)を使用してください。
Signer 抽象化
すべての署名操作は Signer interface (src/lib/signer/types.ts) 経由で実行されます。command 層は credential の種類を知らず、provider が認証 UX を内部に閉じ込めます(Strategy パターン)。
Signer interface
export interface Signer {
readonly kind: 'passphrase' | 'api-key';
readonly humanPresenceRequired: boolean;
readonly capabilities: ReadonlySet<Capability>;
isAvailable(): Promise<boolean>;
enforce(ctx?: SpendContext): Promise<void>;
signMessage(walletId, chainId, message): Promise<OWSSignResult>;
signTransaction(walletId, chainId, txHex): Promise<OWSSignResult>;
signTypedData(walletId, chainId, typedDataJson): Promise<OWSSignResult>;
signAndSend(walletId, chainId, txHex, rpcUrl?): Promise<OWSSendResult>;
signHash(walletId, chainId, hash): Promise<OWSSignResult>;
signAuthorization(walletId, auth): Promise<OWSSignedAuthorization>;
getPublicKey(walletId): Promise<`0x${string}`>;
}2 つの実装
| 実装 | kind | humanPresenceRequired | 経路 | 選択条件 |
|---|---|---|---|---|
PassphraseSigner | passphrase | true | TTY で passphrase 入力 → ローカル復号して署名 | --owner flag 指定、または TTY 検出 |
ApiKeySigner | api-key | false | OWS API key を提示 → server-side 署名 | 非 TTY + credential あり |
humanPresenceRequired flag は owner-only 操作の gate で参照され、agent からの owner-only 実行を構造的に拒否します。
resolveSignerKindForWallet
resolveSignerKindForWallet(walletId) は OWS のウォレット metadata(signer.kind)を読んで、ウォレットごとに適切な SignerKind を返します。factory.ts がこの結果と context(API key の有無)から、最終的な Signer インスタンスを組み立てます。
署名の正規化
返却される署名は 常に 0x プレフィックス付き に正規化されます。OWS server / ローカル署名のどちらでも形式が揃うため、command 層・provider 層は分岐なく利用できます。
エージェントセットアップの統合
kova init の Step 3/4(AI 接続設定)として、エージェントセットアップが内部実行 されます。これにより「ウォレットだけ作って credential が無い」状態を防ぎます。
設定される credential / apiKeyId
AI 接続設定(Step 3/4)で、~/.kova/config.json の profiles[<wallet-name>] に以下が保存されます。
{
"profiles": {
"my-wallet": {
"credential": "kova_xxx...",
"apiKeyId": "key-xxx",
"wallets": ["wallet-xxx"]
}
},
"activeProfile": "my-wallet"
}| フィールド | 意味 | 注入される環境変数 |
|---|---|---|
credential | OWS から発行される API key 文字列 | KOVA_CREDENTIAL(launch が agent に注入) |
apiKeyId | API key を識別する ID | KOVA_API_KEY_ID |
kova launch <agent> はこの 2 つの環境変数を子プロセスへ注入することで、agent から呼ばれる Kova が ApiKeySigner 経路を選択できるようにします。エージェントを直接起動した場合も、新しい Kova プロセスが ~/.kova/config.json から credential を直接読み取るため動作します(ADR-036 v2)。
Cancel 時の挙動
kova init の AI 接続設定(Step 3/4)でユーザーがキャンセル(Ctrl+C / Esc)した場合:
kova initは completion banner に 警告を表示 します- ただし
kova init自体は エラー終了しません(exit 0) - 警告が出ているとき、Next Steps からエージェント起動の案内を外します(不完全な状態での誤誘導を防ぐ)
詳細は init リファレンス を参照してください。
dry-run デフォルト(送金)
Kova の送金コマンド(kova send)は、デフォルトで dry-run(シミュレーション) です。
# dry-run(デフォルト)
kova send --name my-wallet --to 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb --amount 10 --chain base --token USDCdry-run では、トランザクションの構築・ガス代の見積もり・残高の確認・バリデーションがシミュレーションされ、実際の送金は行われません。
実送信するには --broadcast を明示指定します:
kova send --name my-wallet --to 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb --amount 10 --chain base --token USDC --broadcastAI エージェント統合時の推奨フロー
- dry-run で確認 — まず dry-run で送金内容を確認
- ユーザー承認 — dry-run 結果をユーザーに提示し、承認を得る
- broadcast 実行 — 承認後に
--broadcastフラグで実送信
ポリシー制御
ポリシーは API key に関連付けて、agent からの送金・決済・署名を制限する仕組みです。AI エージェントに使わせる場合は 必ずポリシーを設定 してください。
ポリシー評価の流れ
ポリシーテンプレート
kova policy で登録できるテンプレート一覧(policy リファレンス も参照):
| テンプレート ID | 説明 |
|---|---|
allowed_chains | 操作を許可するチェーンを CAIP-2 形式で列挙 |
expires_at | ポリシーの有効期限(ISO 8601 timestamp) |
max_value | ネイティブトークン送金の上限(wei 単位) |
spending_limit | chain × token ごとの日次/月次累積上限 |
ポリシーに違反する操作は POLICY_DENIED で拒否されます:
{
"ok": false,
"error": {
"code": "POLICY_DENIED",
"message": "Transaction exceeds policy maxAmount: 100 USDC"
}
}ポリシーの確認・更新は policy リファレンス、API key の管理は key リファレンス を参照してください。
spending_limit fail-closed
spending_limit テンプレートで作成したポリシーは、agent 経路(非 TTY)の send / call 実行前に signer.enforce(ctx) が OWS server 側で事前評価 します。fail-closed なので、評価できない/超過するケースは すべて拒否 されます。
累積記録
累積額は ~/.kova/spend.json にローカル記録されます(chain × token × 日付ごと)。1 日の累積が daily_limit を超えると、後続の操作は POLICY_DENIED で拒否されます。
enforce(ctx) の責務
Signer.enforce(ctx) は実 RPC 呼び出しの 前 に呼ばれる ctx-aware な事前 gate です:
ApiKeySigner.enforce(ctx)→ OWS server にenforcePolicy(apiKey, ctx)をリクエストし、policy + spending_limit を評価PassphraseSigner.enforce(ctx)→ terminal owner mode のため no-op
ctx には entryPoint / chain(CAIP-2)/ token / amount を渡します。sign* メソッド内部の enforcePolicy(apiKey)(ctx 無し)は tamper detection の defense-in-depth として残されています。
異常系: spending_limit 超過
| ケース | 挙動 | 累積記録先 |
|---|---|---|
1 日累積が daily_limit 以下 | 通過、記録更新 | ~/.kova/spend.json |
1 日累積が daily_limit 超過 | POLICY_DENIED で fail-closed | 記録は更新しない |
enforce 呼び出し失敗(network / OWS error) | fail-closed(拒否) | - |
現状の制約
ERC-20 calldata 内 amount の累積記録は 未対応 です。現状は ERC-20 transfer の calldata 内 amount を spend.json には記録しません。NATIVE シンボル(チェーンのネイティブトークンを表す予約シンボル)の record のみ完全対応しています。
本番環境のベストプラクティス
1. ウォレット管理
- 本番用と開発用を分離 — 開発環境では絶対に本番ウォレットを使わない
- 定期的なバックアップ — 週次または月次でバックアップを取る
- 複数のバックアップ場所 — オフラインストレージ、クラウドストレージ等
2. API key 管理
- 最小権限の原則 — 必要最低限の権限のみを付与
- 定期的なローテーション — 3 ヶ月ごとに API key を再生成
- 使用履歴の監視 — 不審な使用がないか定期的に確認
3. ポリシー設定
- 送金制限の設定 —
kova initは制限なし(permissive)の状態でセットアップを完了する。実運用ではpolicy updateでチェーン制限・送金上限・許可リストを設定する - 段階的な権限管理 — まず permissive で動作確認し、運用に合わせて制約を追加していく
spending_limitを入れる — agent モードの fail-closed 防衛線として有効
4. AI エージェント運用
- dry-run の徹底 — 必ず dry-run で確認してから
--broadcast - ユーザー承認フロー — 高額送金は必ず人間の承認を得る
- ログの記録 — すべてのトランザクションをログに記録
- 異常検知 — 異常なトランザクションパターンをアラート
5. プロンプト汚染の防御
AI エージェントは、悪意のあるプロンプト注入攻撃に脆弱です。以下の対策を推奨します:
- 入力の検証 — ユーザー入力を信頼しない、常にバリデーション
- 出力の検証 — AI エージェントの出力を盲目的に信頼しない
- 人間の確認 — 高リスク操作(owner-only)は必ず人間が確認
- サンドボックス環境 — テスト環境でまず動作確認
6. ハードウェアウォレット・KMS
Kova は現在、ローカル暗号化ウォレットと OWS server-side 署名のみをサポートしていますが、Signer 抽象化により以下の拡張が可能な設計になっています:
- ハードウェアウォレット — Ledger / Trezor 等(
SignerKindにhw-ledger等を追加) - OS Keychain — macOS Keychain / Windows Credential Manager
- KMS (Key Management Service) — AWS KMS / Google Cloud KMS
高額の資産を扱う場合は、これらの統合をお待ちください。
セキュリティインシデント対応
ウォレットが漏洩した場合
- すぐに資産を移動 — 新しいウォレットに全資産を転送
- API key を無効化 — すべての API key を即座に無効化
- ログを確認 — 不正なトランザクションがないか確認
- パスフレーズを変更 — 他のサービスで同じパスフレーズを使用している場合は変更
# 緊急時の資産移動
kova send --name my-wallet --to <new-wallet-address> --amount <all-balance> --chain base --token USDC --broadcast
# active な API key を新規鍵に置き換える
# 注: `kova key rotate` は 1 key 単位の置換 (新規発行 → 旧鍵 revoke) であり、
# 「全 API key の即時無効化」にはなりません。複数 key を保持している場合は
# 各 key を個別にローテートするか、OWS ダッシュボードで一括 revoke してください。
kova key rotate --name <active-key-name>不正なトランザクションを発見した場合
- API key を即座に無効化
- ログを保存 — トランザクション履歴を記録
- 原因を調査 — ポリシー設定、AI エージェントのログ、
~/.kova/spend.jsonを確認 - 再発防止策 — ポリシーを強化、
spending_limitを厳しめに更新、監視を追加
次のステップ
- Wallets — ウォレットの詳細を学ぶ
- Architecture — コンポーネント構成を確認する
- CLI Commands: init — agent セットアップの詳細(
kova initの AI 接続設定フェーズ) - CLI Commands: status — 現在の認証経路 / policy enforcement の確認
- CLI Commands: policy — ポリシーコマンドの詳細
- CLI Commands: key — API key コマンドの詳細
- CLI Commands: sign — Signer 経路の使い分け
- Guides: AI Agent Integration — AI エージェント統合のベストプラクティス