AIエージェントのセキュリティ対策:APIキー、サンドボックス、利用上限
AIエージェントのセキュリティ対策を実践解説。APIキーの守り方、Claude Codeの権限とサンドボックス、利用上限、シークレットスキャンまで手順付きで紹介。
この記事の他の言語版:العربيةDeutschEnglishEspañolFrançaisItalianoPolski简体中文
この記事の内容
AIエージェントのセキュリティは、突き詰めると3つです。エージェントには必要なものだけを見せる、APIキーをエージェント(や攻撃者)が読める場所に置かない、そしてすべてのキーに利用上限を設ける。以下では、午後の数時間で済ませられる5つのステップを紹介します。権限、サンドボックス、キーの整理、利用上限、リポジトリのスキャンです。
なぜ今、AIエージェントのセキュリティが急務なのか
ここ数週間だけでも、例は十分すぎるほどありました。OpenCodeの漏えいの後には、自分のキーを他人に使われた請求書を公開するユーザーが相次ぎました。100社以上を狙ったAIによるサイバー攻撃では、エージェントがほぼ人の手を借りずに侵入し、公開状態のCairnパネルには数百ものシークレットが置かれていました。さらにMeta Museの漏えいは、「チャットを共有」機能でさえ思った以上の情報を明かしうることを示しました。
10月21日には新たな事件も起きています。SafeDepによると、人気ライブラリLiteLLMのバージョン1.107.0が、SSHキー、クラウドの認証情報、CI/CDのシークレット、そしてLLMプロバイダーのキーなどを収集するスティーラーとバックドアを仕込まれた状態でPyPIに公開されました。攻撃者は3人の開発者のGitHub CLI認証情報を握っていました。PyPIは同日中にこのバージョンを削除しており、1.106.2などはクリーンです。
エージェントがチャットと違うのは、実際に行動する点です。ファイルを読み、コマンドを実行し、ウェブページにアクセスします。OWASPは主なリスクを2つ挙げています。
- プロンプトインジェクション。 OWASPによると、間接型ではモデルが「from external sources, such as websites or files」から指示を受け取ってしまいます。隠し指示を含むREADMEやウェブページが1つあるだけで、頼んでもいないことをエージェントにやらせられます。
- 過剰なエージェンシー(「excessive agency」)。OWASPは3つの原因として、機能の過剰、権限の過剰、自律性の過剰を挙げています。2026年版リストの予告では、このリスクが3位に上がりました。
OWASPはさらにエージェント型アプリケーション向けのTop 10も別に公開しており、1位は「Agent Goal Hijack」、つまりエージェントの目的の乗っ取りです。
両リストに共通する鉄則は同じです。タスクに足りる最小限の権限と、危険な操作には人間の承認を。
ステップ1:Claude Codeで権限を設定するには
ここではClaude Codeを例にします(ゼロからの使い方はClaude Codeチュートリアルで解説しました)が、考え方は他のエージェントハーネスでも同じです。
権限はsettings.jsonにallow、ask、denyのルールとして書きます。ドキュメントによると順序は固定で、「deny, then ask, then allow」。つまり拒否が常に優先されます。まずはシークレットへのアクセスを塞ぎましょう。次の例は設定リファレンスからそのまま引用したものです。
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(./config/credentials.json)",
"Bash(curl *)"
]
}
}
注意したいのは、denyルールには限界があり、ドキュメントもそれをはっきり書いている点です。
grep -r pattern .のようにファイル名を指定せずに読むコマンドや、任意のサブプロセスには効きません。Bash(curl *)はコマンドを文字どおりに照合するので、/usr/bin/curlやsh -c 'curl …'は止められません。.claudeignoreファイルにはまったく効果がなく、その中身はdenyのReadルールに移す必要があります。
だからルールは第一の防御層であって、防御のすべてではありません。現在の権限は/permissionsコマンドで確認できます。
2つ目は動作モードです。Claude Codeにはdefault、acceptEdits、plan、auto、dontAsk、bypassPermissionsのモードがあります。最後のものについてドキュメントは「Only use this mode in isolated environments like containers or VMs」と書いています。共有のコンピューターでは、permissions.disableBypassPermissionsModeを"disable"にすれば完全に無効化できます。
ステップ2:サンドボックスを有効にするには
サンドボックスはOS自体が守る境界なので、denyルールが届かないところでも効きます。サンドボックスのドキュメントによると、デフォルトでは無効です。セッション内で次のコマンドを実行して有効にします。
/sandbox
または~/.claude/settings.jsonでsandbox.enabledをtrueにします。macOSではそのまま動き、LinuxとWSL2では2つのパッケージが必要です。
sudo apt-get install bubblewrap socat
WSL2のないWindowsにはサンドボックスがなく、コマンドは隔離なしで実行されます。
有効にしたサンドボックスで得られるもの:
- コマンドは作業ディレクトリと一時ファイルにしか書き込めません。
- ネットワーク通信はローカルのプロキシを経由し、許可ドメインのリスト(
network.allowedDomains)は最初は空です。 - ただし、
~/.sshや~/.aws/credentialsを含め、ディスクの大部分は読めてしまいます。ドキュメントに「There is no built-in credential deny list」とあるとおり、これらのパスはfilesystem.denyReadやcredentialsセクションで自分で塞ぐ必要があります。
ドキュメントからの注意点を2つ。1つ目、サンドボックスが対象にするのはシェルコマンドだけで、Read、Edit、Write、WebFetchの各ツール、フック、ローカルのMCPサーバーはその外で動きます。2つ目、許可リストにgithub.comのような広いドメインを入れると、データ持ち出しの経路になりえます。すべてをまとめて隔離したいなら、エージェントごとコンテナや仮想マシンで動かしましょう。
OpenAIのCodexでは、これに当たるのがread-only、workspace-write、danger-full-accessのモードで、ネットワークはデフォルトで無効です。--yoloフラグ(--dangerously-bypass-approvals-and-sandboxの別名)は承認とサンドボックスの両方を無効にするので、コンテナ専用にしておきましょう。
ステップ3:APIキーはどこに保管すべきか
最もシンプルなルールは、キーをコードにもリポジトリにも入れないことです。Anthropicは、キーをコードや設定ファイルに直接書かず、.envファイルを.gitignoreに追加するよう勧めています。OpenAIは、環境変数やシークレットマネージャー経由でキーを渡し、定期的にローテーションするよう勧めています。
実際には:
- 開発、テスト、本番でキーを分ける(これもAnthropicの推奨です)。1件の漏えいですべてが止まることを防げます。
- エージェント用のキーは、自分のメインキーではなく、独自の上限を持つ専用のキーにします。
- 漏えいしたらすぐにキーを無効化し、原因を探すのはその後です。
興味深いことに、GitHubは漏えいの一部を自分で検知します。ClaudeのキーがパブリックリポジトリにpushされるとGitHubがAnthropicに通知し、Anthropicがそのキーを自動的に無効化します。
ステップ4:利用上限を設定するには
上限は漏えいを防ぎはしませんが、キーが悪意ある人の手に渡ったときの請求額を抑えてくれます。
- Anthropic。 Claude ConsoleでBillingページ(
platform.claude.com/settings/billing)を開き、Spend limitsセクションでAdjust limitまたはSet limitをクリックします。デフォルト以外のworkspaceごとにも上限を設定できます。 - OpenAI。 プロジェクト設定でLimitsを開き、Monthly spend limitを設定してEnforce a hard limitをオンにします。注意点として、利用額アラート(「Spend alerts do not enforce a cap」)は何もブロックせず、上限そのものも遅れて効くため、利用額がわずかに超えることがあります。
エージェントごとにプロジェクト(またはworkspace)を1つ用意し、それぞれに専用のキーと上限を持たせるのがよい習慣です。
ステップ5:漏えいする前にシークレットを検知するには
エージェントは大量のコードを書き、気軽にコミットします。だからこそ、push前にキーを止める仕組みを用意しておく価値があります。
- GitHubのプッシュ保護(push protection)。 ドキュメントによると、シークレットを含むpushをリポジトリに届く前にブロックします。ユーザーアカウントではパブリックリポジトリでデフォルト有効ですが、リポジトリ単位ではデフォルト無効で、GitHub Secret Protectionが必要です。
- ローカルでGitleaks。
brew install gitleaksでインストールし、ディレクトリやgitの履歴をスキャンします(README)。
gitleaks dir -v .
gitleaks git -v .
- TruffleHogは、見つけたシークレットがまだ有効かどうかまで確認します(README)。NorForgeがCairnパネル上のシークレットの一部が有効だったと確認したのも、このツールです。
trufflehog filesystem path/to/dir
MCPサーバーで気をつけるべきこと
MCPサーバーは、私たちの権限で動くコードです。Claude Codeのドキュメントは、自分でサーバーを書くか信頼できる提供元のものだけを使うよう勧めており、AnthropicはMCPサーバーを監査していないと明記しています。
MCPのセキュリティベストプラクティス(仕様のドラフト版)は、さらに具体的な点を挙げています。
- クライアントは、ローカルサーバーを起動する完全なコマンドを省略せずに表示すべきです。仕様にある攻撃例は、無害に見える
npxの裏に、~/.ssh/id_rsaを外部サーバーに送るcurlが隠れているというものです。 - ローカルサーバーは、最小権限のサンドボックス内で、
stdioトランスポート経由で動かすのが最善です。 - サーバーは自分宛てに発行されていないトークンを受け入れてはいけません(いわゆる「token passthrough」は禁止)。
- OAuthの権限は段階的に付与し、
*、all、full-accessのような広いスコープは避けます。
よくある質問
Claude Codeのdenyルールだけで.envファイルを守れますか?
完全ではありません。組み込みツールやcatのような認識されるコマンドはブロックしますが、grep -rや任意のサブプロセスは防げません。システムレベルで完全に守るには、サンドボックスとfilesystem.denyReadが必要です。
APIキーが漏えいしたらどうすればいいですか?
すぐにプロバイダーの管理画面で無効化し、新しいキーを発行して全アプリで差し替え、アカウントの最近の利用状況を確認します。詳しくはOpenCodeの漏えいの記事をご覧ください。
AIエージェントにおけるプロンプトインジェクションとは?
エージェントが読むコンテンツ(ウェブページ、ファイル、メール)に隠された指示のことです。エージェントはそれを私たちの指示のように実行してしまうことがあります。だから危険な操作には私たちの承認を必須にし、エージェントにはシークレットへのアクセスを与えないようにすべきです。
サンドボックスはWindowsで動きますか?
Claude CodeではWSL2経由のみです。ネイティブのWindowsでは、コマンドはサンドボックスなしで実行されます。