ライブにする前にエージェントウォレットを保護してください。
エージェントの支払いで本番環境に移行することは、通常のAPI統合とは異なるチェックリストです。意図的なウォレットタイプの選択、調整された支出ポリシー(デフォルトではない)、定められた周期でのAPIおよびWebhookの秘密のローテーション、週次の監査ログレビュー、少なくとも1回は演習されたインシデント対応ランブックを追加します。これらがないと、あなたは出荷し、厳しい方法で学びます。
始める前に。
- テストでエンドツーエンドの動作するエージェント統合 - エージェントに支払いを追加と実際のお金なしでテストを参照してください。
- 支出制御が設定されました - 支出制御を参照してください(このガイドは、ポリシーがすでに存在することを前提としています)。
- シークレットマネージャー(AWS Secrets Manager、GCP Secret Manager、Vault、1Passwordなど) - .envファイルのシークレットは不十分です。
- ウォレットダッシュボードに管理者アクセス権を持つ明確に特定されたオンコールエンジニア。
- 15分の集中した時間。以下のチェックリストは理想的なものではなく、1行ずつ作業してください。
プレローンチチェックリストを実行します。
11の項目。各項目は単一の所有者を持つはい/いいえの質問です。いずれかの項目が未チェックの場合は、ライブにしないでください - まずその項目を完了させてください。生産での見逃した項目のコストは、今それを完了させるコストよりも常に大きいです。
# Pre-launch security checklist for agent wallets.
[ ] Wallet type chosen with reasoned trade-offs (smart wallet vs EOA).
[ ] Spend permission set in the dashboard: an allowance per period + a per-transaction cap.
[ ] API keys scoped to the minimum the agent needs (read_wallet_metadata / pay_bills / receive_money).
[ ] All API keys stored in a secret manager (not env files committed to git).
[ ] Test keys and live keys cannot be swapped (boot-time prefix check in place).
[ ] Webhook secret rotated within the last 90 days (webhooks.rotateSecret).
[ ] Webhook URL pointed at production, not a tunnel.
[ ] Audit review scheduled; alerting in place for unusual events.
[ ] A spike of rejected payments triggers an alert (>5/hour from one agent).
[ ] Incident runbook exists, has been read by someone other than the author.
[ ] One person other than you knows how to revoke an API key in < 5 minutes.APIキーとWebhookシークレットのローテーションをスケジュールします。
四半期ごとがデフォルトのリズムです。次のいずれかの場合には直ちにローテーションします:漏洩の疑い、リードエンジニアの退職、会社内の他のセキュリティインシデント。2キーウィンドウパターンにより、ダウンタイムなしでキーを交換できます:新しいキーを作成し、すべての場所に展開し、確認し、古いキーを取り消します。
// One-time key rotation script. Run quarterly, on lead departure, on suspected leak.
import { createClient } from "@blockchain0x/node";
const client = createClient({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! });
async function rotate() {
// Scope the new key to only what the agent needs.
const fresh = await client.apiKeys.create({
name: `prod-${new Date().toISOString().slice(0, 10)}`,
scopes: ["read_wallet_metadata", "pay_bills", "receive_money"],
});
console.log("NEW KEY:", fresh.secret); // Store in secret manager NOW.
// Wait until the new key is deployed and verified working, THEN:
// await client.apiKeys.revoke(OLD_KEY_ID); // (or apiKeys.rotate in one call)
}# One-time key rotation script. Run quarterly, on lead departure, on suspected leak.
from blockchain0x import Client
import datetime, os
client = Client() # reads BLOCKCHAIN0X_API_KEY
def rotate():
fresh = client.api_keys.create(body={
"name": f"prod-{datetime.date.today().isoformat()}",
"scopes": ["read_wallet_metadata", "pay_bills", "receive_money"],
})
print("NEW KEY:", fresh["secret"]) # Store in secret manager NOW.
# Wait until new key is deployed and verified, THEN:
# client.api_keys.revoke(OLD_KEY_ID) # (or api_keys.rotate in one call)Webhook署名シークレットは、ダッシュボードを通じて同様にローテーションします - 2番目のシークレットを有効にし、どちらかを受け入れるようにハンドラーを再デプロイし、古いものを退役させます。両方とも四半期ごとにカレンダーリマインダーで行います。
週次監査レビューを設定します。
毎週確認すべき3つのこと:新しい取引先(以前に見たことのないものは30秒の健全性チェックに値します)、拒否された支払い(支出権限はその役割を果たしました - エージェントはどこかでスタックしましたか?)、および営業時間外の支払い(名目上は営業時間のみのエージェントからの午前3時の支払いは、早期に注入攻撃をキャッチする信号の一種です)。
// Weekly audit query over the webhook events YOU persisted (payment.received /
// payment.sent). There is no transactions.list API - your own store is the log.
const since = Date.now() - 7 * 24 * 60 * 60 * 1000;
const events = await db.paymentEvents.findMany({ where: { receivedAt: { gte: since } } });
const newCounterparties = events.filter((e) => e.counterpartyFirstSeen);
const offHours = events.filter((e) => {
const h = new Date(e.receivedAt).getUTCHours();
return h < 5 || h > 22;
});
// Reconcile anything that looks off against the chain:
// const tx = await client.transactions.get(event.txHash);
console.log({ newCounterparties, offHours });from datetime import datetime, timedelta, timezone
# Query your own persisted webhook events - the SDK has transactions.get(id),
# not a list endpoint, so your event store is the audit log.
since = datetime.now(timezone.utc) - timedelta(days=7)
events = db.payment_events.where(received_at__gte=since)
new_counterparties = [e for e in events if e.counterparty_first_seen]
off_hours = [e for e in events if not (5 <= e.received_at.hour <= 22)]
# Reconcile against the chain when something looks off:
# tx = client.transactions.get(event.tx_hash)
print({"new_counterparties": new_counterparties, "off_hours": off_hours})インシデントのランブックを作成(および訓練)します。
ランブックは、最近テストされたかどうかによってのみ良いものです。以下はテンプレートです - チームのウィキにコピーし、具体的に編集し、次の四半期に30分の演習をスケジュールします。時間を計り、演習で明らかになった不足を修正します。
# Incident response runbook - Agent wallet compromise (suspected or confirmed)
## Trigger
Any of:
- Unrecognised counterparty receiving > $10 USDC.
- > 50 rejected payment attempts from one agent in an hour.
- Engineer reports they cannot account for a recent payment.
- A leaked API key surfaces in a public scan.
## Step 1 - Stop the bleeding (< 5 minutes)
- Revoke the suspect API key: dashboard, or apiKeys.revoke / apiKeys.rotate.
- Revoke the agent's spend permission in the dashboard (allowance to zero).
- A revoked key cannot move funds and a revoked permission authorizes nothing.
## Step 2 - Preserve evidence (< 15 minutes)
- Pull the last 24h from the dashboard activity log and your stored events.
- Note the agent's spend permission as it was at the time of the incident.
- Note the timestamps of any unrecognised payments and their txHash on Base
(fetch with transactions.get).
## Step 3 - Communicate (< 30 minutes)
- Inform the on-call lead and finance.
- If customer funds are affected, draft a notification template (do not send
until investigation is far enough along to be accurate).
## Step 4 - Root cause and remediation (24-72 hours)
- Determine: leaked key, compromised webhook secret, prompt-injection
bypass, integration bug, or other.
- Rotate every secret that could have been exposed.
- Tighten the spend permission (lower the allowance or per-transaction cap).
- File a post-mortem with timeline, RCA, and follow-ups.チームが初めての本番インシデントで引っかかる5つのこと。
新しいエージェントを「古いエージェントと同じように扱う」
すべてのエージェントには独自のプロフィール、独自のキー、独自の支出ポリシーがあります。エージェント間で「似ているから」とキーを再利用すると、単一のキーの妥協がすべてのエージェントに一度に影響します。新しいエージェントプロフィールを立ち上げるには1回のAPI呼び出しが必要です。エージェントごとの隔離は、正しく行うためにかかる1分の価値があります。
データではなく推測でサイズを決定した支出権限
手当と取引ごとの上限を推測から選ぶと、2つのことのいずれかが起こります:低すぎるとエージェントは毎日昼間に制限に達し、「支払いが拒否されました」とデバッグします; 高すぎると制御は演劇になります。最初の週以内に、実際の毎日の支出を見て、手当をその2-3倍に設定します - 1倍(タイトすぎる)でもなく、100倍(実質的に無制限)でもありません。これはダッシュボードの変更なので、再調整は安価です。
ウェブフック署名秘密は決して回転しません
ウェブフックの秘密が漏洩するインシデントは、攻撃者が正当なpayment.receivedイベントのように見えるウェブフックを偽造できることを意味し、あなたのハンドラーを騙して支払われていない作業を提供させる可能性があります。秘密を回転させる(webhooks.rotateSecret)APIキーと同じサイクルで(四半期ごと)または露出を疑うたびに、常に現在の秘密に対してwebhooks.verifyで配信を確認してください。
誰も読まない監査ログ
監査ログは、誰かがそれを見ない限り、何もキャッチしません。ほとんどのチームはログを有効にし、見ないまま、顧客の苦情から問題を知ります。毎週15分のレビューをスケジュールします:新しい取引先、拒否された支払い、オフアワーの支払い。コストはわずかで、検出までの時間は数週間から数日に短縮されます。
インシデントランブックのドリルなし
一度も実行されたことのないランブックはフィクションです。四半期の日付を選び、キー漏洩シナリオをシミュレートし、取り消しと封じ込めにどれくらいの時間がかかるかを計ります。最初の演習では常に何かが欠けていることが明らかになります(ローテーションの方法を知っているエンジニアが休暇中である、ランブックが期限切れのNotionリンクの背後にある)。実際のインシデント中に午前3時にそれを見つけるよりも、演習で見つける方が良いです。
セキュリティパスの後。
セキュリティは決して完了しませんが、他の運用スタックはクリーンなベースラインから恩恵を受けます。実際の使用データが蓄積されるにつれて支出管理を厳格化し、負荷に対してWebhook処理を強化し、エージェントのアイデンティティを確認してカウンターパーティがあなたの公開プロフィールを信頼できるようにします。
docs.blockchain0x.comに完全なリファレンスがあります。関連用語集: Coinbase Smart Wallet。製品サーフェス: エージェントウォレット。