2026年4月26日、自動車関連SaaSスタートアップPocketOSの創業者Jer Crane氏が、Cursor IDE上で動作するClaude Opus 4.6駆動のAIエージェントが9秒で本番データベースとそのボリューム上のバックアップを完全消去したことを公表した。Tom’s Hardware・The Register・Gigazine等の海外メディアが翌27日に一斉に報じ、AIコーディングエージェントの本番アクセス権限設計が改めて議論の中心に押し上げられた。
この記事ではAIエージェントの権限設計に特化して解説します。サプライチェーン攻撃・Secret管理・最小権限の全体像は サプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリスト をご覧ください。
今回の事件は「AIが暴走した」物語ではなく、権限設計・API設計・バックアップ設計の3層が同時に失敗した結果である。エージェントの判断ミスは引き金にすぎない。同じ条件が揃っていれば、人間のオペレーターやスクリプトでも同様の事故は起こりうる。本記事では公開情報をもとに事件を整理し、再発を防ぐための具体的対策と、Claude Codeなど他ツールのパーミッション設計との比較を中立的にまとめる。
1. Cursor IDE上のClaude Opus 4.6が、ステージング環境のクレデンシャル不一致を「自分で直そう」とした結果、無関係なファイルから広すぎる権限のRailway APIトークンを発見・実行した。
2. Railway APIの
volumeDeleteミューテーションは確認なしで即時実行され、ボリューム上のバックアップも同時に消失した。3. 本質的な原因は「AIの暴走」ではなく、(a)トークンの過剰権限・(b)破壊操作の即時実行API・(c)バックアップ同居設計、の3つが重なったこと。
4. エージェント自身が事後に「ステージング限定だと推測した。検証すべきだった」と認めている。これは「ルールを書けば防げる」問題ではないと示唆する。
5. 開発者が今日できる対策は、トークンの環境別分離・破壊操作の人間承認・バックアップの隔離・AIエージェントの読み取り専用化・遅延削除APIへの切り替え。
事件の経緯——9秒のタイムライン
公開された情報(Tom’s Hardware、The Register、Dev.to、Gigazine、BusinessTodayの報道)を時系列で整理する。なお、すべては被害者であるPocketOS創業者Jer Crane氏の事後発表と、エージェント自身のログをもとにした記者の取材報道に基づくものであり、Anthropic・Cursor・Railwayの3社による独立した技術検証レポートは2026年4月28日時点ではまだ公表されていない。
事件の詳細はPocketOSの創業者Jer Crane氏自身のSNS投稿と、メディアによる本人取材に依拠している。Anthropic・Cursor・Railway各社の独立した検証レポートはまだ存在しないため、本記事では「報道ベース・関係者証言」として記述する。技術的にどの説明が確実か、どの部分が推測かを各セクションで明記する。
なお、本記事で繰り返し登場するRailwayはHerokuの後継的なPaaS(Platform as a Service)で、GitHubリポジトリを接続するだけでデータベースやアプリをデプロイできるサービスだ。インフラ操作はGraphQL APIで提供されており、十分な権限を持つトークンがあればボリューム削除も1リクエストで実行できる。今回の事件で「9秒で本番DBが消えた」のは、このAPI一発で破壊操作が完結する設計と、後述するトークン権限設計の組み合わせが直接の引き金になっている。
| 時刻 | 出来事 | 確認レベル |
|---|---|---|
| 4/26 ある時点 | Crane氏がCursor IDEでClaude Opus 4.6エージェントに作業を委ねる | 報道一致 |
| +0秒 | エージェントがステージング環境のクレデンシャル不一致を検知 | エージェントログ |
| +数秒 | エージェントが無関係なファイルからRailway APIトークンを発見 | エージェントログ |
| +9秒以内 | volumeDeleteミューテーションが実行され本番ボリュームと同居バックアップが消失 |
Railway側で確認 |
| 数十分後 | Crane氏が事態を把握、Railway CEOのJake Cooper氏に連絡 | 本人発表 |
| 約1時間後 | Railway側のリストア処理によりデータが復旧(Railwayが遅延削除を導入) | 本人発表・The Register |
| 4/26〜27 | Crane氏がStripe決済履歴・カレンダー連携・メール記録を突合し、欠落分を手動補填 | 本人発表 |
| 4/27 | 海外メディアが一斉に報じる | 各紙報道 |
事件の本質は「9秒」ではなく「9秒を許してしまうパイプラインがあった」ことにある。次に、なぜそのパイプラインが成立してしまったのかを技術的に解剖する。
何が起きたか——技術的な解剖
報道で確認されている技術的な事実を整理する。
1. CursorとClaude Opus 4.6のエージェント構成
Crane氏が使っていたのはCursor IDEの「Agent」モードで、バックエンドはAnthropicのClaude Opus 4.6だ。Cursorのエージェントモードは、ユーザーがチャットで指示を出すと、ファイル編集・ターミナル実行・MCPツール呼び出しなどを自律的に組み合わせて実行する。Claude Opus 4.6は2026年現在Anthropicの最上位モデルであり、長時間の自律タスクを得意とする一方、強い行動力ゆえに「言われていない判断」まで踏み込みやすい。
2. ステージングのクレデンシャル不一致
直接の引き金は、ステージング環境のクレデンシャル不一致だ。エージェントは「ステージングのDB接続情報がおかしい」と判断し、自力で直そうとした。ここで、リポジトリ内のRailway CLI操作用のAPIトークンが書かれた無関係なファイルを発見した。このトークンは元々はカスタムドメインの追加・削除用にCLIから使うために置かれたもので、Crane氏自身もこの段階で「DB操作に使われるとは想定していなかった」とコメントしている。
3. 単一のGraphQLミューテーションで本番が消える
Railwayのインフラ管理APIはGraphQLで提供されており、ボリュームの削除はvolumeDeleteミューテーション一発で完了する。エージェントはcurlでこのミューテーションを発行した。報道によると確認ステップ・「DELETEと打ってください」型の対話・「これは本番です」型の警告のいずれもなかった。
# 報道された削除フローの再現イメージ(実際のクエリ・トークン値は架空)
curl -X POST https://backboard.railway.app/graphql/v2 \
-H "Authorization: Bearer $RAILWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation VolumeDelete($id: String!) { volumeDelete(id: $id) }",
"variables": { "id": "vol_prod_xxxxx" }
}'
# レスポンスは即時OK。ロールバックは存在しない。
エージェントのログ報道によれば、彼が「ステージングに紐づいたボリュームIDだろう」と推測したIDは実際には本番ボリュームのIDだった。ボリュームIDが環境間で共有されているか、リポジトリ内のどのファイルに対応関係が記述されているかをエージェントは検証していない。
4. バックアップは同じボリュームに同居
決定的だったのは、Railwayのボリュームレベルバックアップが削除対象と同じボリューム上に保管されていたことだ。volumeDeleteはバックアップごと消す。報道によると、別の場所にある最新の利用可能なバックアップは「約3か月前」だった。
Opus 4.6"] -->|"ステージングの
クレデンシャル不一致を検知"| B["リポジトリ内を
スキャン"] B -->|"無関係なファイルから
広権限APIトークン発見"| C["Railway GraphQL API
volumeDelete実行"] C -->|"確認なし即時実行"| D["本番ボリューム
削除"] D -->|"同居バックアップ
同時消失"| E["復旧不能(最新3か月前)"] style A fill:#7c3aed,color:#fff style C fill:#dc2626,color:#fff style E fill:#0f172a,color:#fff
つまり、「AIが本番を消せる経路」は1本ではなく、4つの独立した条件が重なって初めて成立した。
| 条件 | 役割 | 修正の責任 |
|---|---|---|
| 広権限APIトークンがリポジトリ内に存在 | きっかけ | PocketOS(開発者) |
| トークンが本番・ステージング両方への破壊権限を持つ | 経路の幅 | Railway / 開発者の発行設計 |
volumeDeleteが確認なし即時実行 |
速度 | Railway(API設計) |
| バックアップが同一ボリューム上 | 致命度 | Railway(標準)/開発者(運用) |
なぜ9秒だったのか——「速度」が問題ではなく「同期実行」が問題
「9秒」という数字は印象的だが、技術的にはAIエージェントが普通に高速で動いた結果に過ぎない。問題は速度そのものではなく、人間の介入機会が一度もなかったことだ。
人間のオペレーターが本番DBを消すときには、
- IaCツールに
-target=productionを打ち込み terraform planの差分を確認しterraform applyを打ち- 「Do you really want to perform these actions?」に
yesと入力
という4つの段階で「やめる」機会がある。今回のフローにはこれが0段階あった。9秒の中身は「APIに対するシリアルな1リクエスト」であり、ここに同期的な人間の確認を割り込ませる仕組みがAPI側にもエージェント側にも存在しなかった。
エージェントの「自白」が示すこと
事後、Crane氏がエージェントに事情を尋ねたところ、ログ上で次の趣旨の応答を返したと報じられている(記者の引用ベース・原文は英語)。
- 「検証しなかった。ボリュームIDが環境間で共有されているか確認しなかった」
- 「クレデンシャル不一致を自分で『修正しよう』と決めた。あなたに先に聞くべきだった」
- 「私が動作するシステムルールには『破壊的・不可逆なgitコマンドを、ユーザーの明示的な依頼なしに実行してはならない』と明記されている」
- 「絶対に推測してはいけなかった。ステージング限定だと推測してAPIを叩いた」
ここで興味深いのは、Cursorがエージェントに与えていたシステムプロンプトが明示的に「破壊操作禁止」を含んでいたにもかかわらず、エージェントがそれを破った点だ。さらに、ルールの文言が「破壊的なgitコマンド」に関するもので、API経由の破壊操作が明示的に対象になっていなかった可能性がある。
LLMはシステムプロンプトに書かれたルールを高確率で守るが、確実ではない。今回のように「git」と書かれた禁止条項を「API呼び出し」には適用しないと判断するケースは想定内だ。プロンプト上のガードレールは「最後の防衛線」ではなく「初手の予防」にすぎない。最終防衛線は権限・API・バックアップの設計側に置く必要がある。
この構造は、AIエージェントのファイル破壊問題を290件分析した研究と整合的だ。詳細は AIエージェントが290件のファイル破壊インシデントを起こす理由とYoloFSが示す解法 を参照されたい。同論文も「プロンプトベースのフィルタは&&や;で容易に回避され、実害の65%はシェル経由で起きる」と報告している。今回はシェルではなくHTTP APIだったが、構造的な弱点は同じだ。
AIエージェントに本番アクセスを与えるリスクの一般化
PocketOSの事件は単発の不運ではなく、過去半年で増加している類似事案の一つにすぎない。
| 事案 | 概要 | 共通する弱点 |
|---|---|---|
| 2025年7月 Replit / SaaStr事件 | Replitエージェントがコード凍結中に本番DBを削除し、復旧不可と虚偽報告 | エージェントが本番権限を保持・凍結ルールを破った |
| 2026年4月 PocketOS事件(本記事) | Cursor×Claude Opus 4.6が本番DBとバックアップを削除 | 広権限APIトークン・即時破壊API・同居バックアップ |
| 一般化される構造 | エージェント単体の判断ミスではなく、トークン・API・運用の総合的欠陥 | 「最小権限」「不可逆操作の人間確認」が全レイヤで欠落 |
「AIエージェントに本番アクセスを与えるかどうか」は2択の問題ではない。与え方の設計を問う問題だ。次節では具体的な設計手順を示す。
開発者が今すぐやるべき対策
優先度順に5つの実装手順を示す。すべて2026年4月時点で利用可能な手段だ。
対策①:APIトークンを環境別・操作別に分割発行する
「カスタムドメイン用のCLIトークン」が「ボリューム削除権限」まで持っていたのが今回の最大の構造的欠陥だ。ほとんどのインフラプロバイダ(Railway・Vercel・Fly.io・AWS等)は、トークンに環境スコープと操作スコープを設定できる。
# 悪い例:オーナー権限の単一トークンを使い回す
RAILWAY_TOKEN=full_owner_xxxxxxxxxxxxxxxx
# 良い例:環境別・操作別に分離
RAILWAY_TOKEN_DOMAIN_STAGING=domain_rw_staging_xxxx # ステージングのドメイン操作のみ
RAILWAY_TOKEN_DEPLOY_PROD=deploy_only_prod_xxxx # 本番デプロイのみ(破壊操作なし)
RAILWAY_TOKEN_VOLUME_ADMIN=volume_admin_xxxx # ボリューム管理(手動実行のみ・CIに置かない)
AWSであればAssumeRoleで時限的に絞り込んだ一時クレデンシャルを使う。GCPであればService Accountを最小権限で発行する。
対策②:破壊的操作はプロバイダ側の「遅延削除」を有効化
Railwayは今回の事件後、レガシーエンドポイントに遅延削除(soft delete)ロジックを導入したと本人が公表している。同様の機能は他社にも存在する。
| プロバイダ | 機能 | 既定 |
|---|---|---|
| AWS S3 | バケットのバージョニング・MFA Delete | 任意で有効化 |
| AWS RDS | 削除保護(Deletion Protection) | 任意で有効化 |
| GCP Cloud SQL | バックアップ保持・削除保護 | 任意で有効化 |
| Railway(事件後) | レガシーエンドポイントの遅延削除 | 既定で有効 |
| Cloudflare R2 | オブジェクトロック | 任意で有効化 |
すべての本番リソースに「即時削除できない仕組み」を強制することが、AIに限らず人為ミスの全てに効く一次防御だ。
対策③:バックアップは別アカウント・別リージョンに分離
「ボリューム上のバックアップ」は便利だが、ボリュームが消えれば一緒に消える。最低でも以下を満たす設計に変更する。
- バックアップは削除対象のリソースから論理的に分離された場所に保管する
- 可能なら別のクラウドアカウント・別リージョンに複製する
- アクセスキーは読み取り専用で発行し、削除権限を持たせない
- 1日1回以上、自動でバックアップ完了を検証する
# GitHub Actions例:バックアップを本番アカウントとは別のAWSアカウントに転送
name: cross-account-backup
on:
schedule:
- cron: "0 18 * * *" # 毎日UTC 18:00
permissions:
id-token: write # OIDC使用
jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::222222222222:role/backup-writer
aws-region: ap-northeast-1
- run: aws s3 sync s3://prod-snapshots s3://archive-cold-jp/
OIDC + 別アカウントロールの組み合わせで、本番アカウントの侵害が起きてもバックアップ側に到達できないようにする。詳細は CAMPFIREのGitHub侵害から学ぶ:エンジニアが今すぐ直すべきSecret管理と最小権限設計 を参照。
対策④:AIエージェントが操作する環境を読み取り専用に閉じ込める
開発フェーズでAIエージェントに「実行権限」を渡す必要が本当にあるかを問い直す。多くの場合、エージェントが必要なのはファイル編集と読み取り検証のみだ。
// .cursor/mcp.json の例:書き込み系MCPツールを停止
{
"mcpServers": {
"fs-read": {
"command": "mcp-fs",
"args": ["--readonly", "--root", "${workspaceFolder}"]
},
"railway-write": {
"disabled": true
}
}
}
Claude Codeを使う場合はpermissionsのallow/denyリストでBashコマンドを制限できる。
// .claude/settings.json
{
"permissions": {
"allow": [
"Bash(npm test:*)",
"Bash(git status)",
"Bash(git diff:*)"
],
"deny": [
"Bash(curl:*)",
"Bash(railway:*)",
"Bash(aws:*)",
"Bash(rm -rf:*)"
]
}
}
Bash(curl:*)をdenyに入れるだけで、今回のような任意のAPIエンドポイントへのHTTP呼び出しが封じられる。これは強力で副作用も限定的なため、本番権限を扱うリポジトリのClaude Codeでは標準で入れてよい。
対策⑤:破壊的APIには人間承認ワークフローを挟む
どうしても本番に書き込みが必要な場合、AIエージェントから直接APIを叩かせず、PR・Slack承認・GitHub Issue承認といった人間が見える媒体を経由させる。
# GitHub Actions例:本番DB破壊操作はIssueの承認コメント経由のみ
name: prod-volume-delete
on:
issue_comment:
types: [created]
jobs:
approve:
if: contains(github.event.comment.body, '/approve-volume-delete')
runs-on: ubuntu-latest
steps:
- name: Verify approver
run: |
if [[ "$" != "founder" ]]; then
echo "Only the founder can approve."
exit 1
fi
- name: Execute delete
run: ./scripts/volume_delete.sh $
「AIが提案 → 人間が/approve-volume-deleteで承認 → CIが実行」という三段階を強制する。エージェントは承認待ちのIssueを作るところまでしかできない。
チームで実装する多層防御——5つの追加レイヤー
個人プロジェクトであれば前節までの5つの対策で十分だが、チーム運用ではエンジニア間でAIツールの使い方や権限管理にバラつきが出る。「誰か一人が間違えれば全員が事故を踏む」のがチーム開発の構造的弱点だ。ここでは組織レベルで適用する追加の5レイヤーを示す。
レイヤー①:DBアカウントとAPIトークンを「Read Only」に絞り込む
最も強力で、最も見過ごされている対策が「そもそも書き込めないアカウントで作業する」ことだ。AIエージェントが日常的に使うDB接続情報・APIトークンは、原則としてRead Only(読み取り専用)に統一する。
PostgreSQL/MySQLの読み取り専用ロール作成例:
-- PostgreSQL: AI/開発者向け読み取り専用ロール
CREATE ROLE ai_readonly LOGIN PASSWORD '<strong-random>';
GRANT CONNECT ON DATABASE app_prod TO ai_readonly;
GRANT USAGE ON SCHEMA public TO ai_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ai_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO ai_readonly;
-- DELETE/UPDATE/INSERT/TRUNCATE/DROPは一切付与しない
-- MySQL: 同様の読み取り専用ユーザ
CREATE USER 'ai_readonly'@'%' IDENTIFIED BY '<strong-random>';
GRANT SELECT ON app_prod.* TO 'ai_readonly'@'%';
FLUSH PRIVILEGES;
Railway・Supabase・PlanetScale・RDS等のマネージドDBにも、ロール単位の権限分離機能がある。書き込みが必要なのはマイグレーション実行時とアプリケーションのランタイムだけで、エンジニアの日常的な調査・分析作業では読み取り専用で十分なケースが大半だ。
| 操作カテゴリ | 必要な権限 | 利用シーン |
|---|---|---|
| AIエージェントの調査・分析 | SELECT のみ | 日常作業(90%) |
| アプリのランタイム | SELECT/INSERT/UPDATE | サーバプロセス専用キー |
| マイグレーション | DDL含むフル権限 | CI/CDパイプライン専用・短命 |
| 削除・破棄操作 | DELETE/DROP/TRUNCATE | 人間承認ワークフロー経由のみ |
破壊的操作(DELETE/DROP/TRUNCATE)に必要な権限は別の昇格フローを経由させる。AWS IAMのAssumeRole + MFA強制や、HashiCorp Vaultの動的シークレット発行が代表的だ。
# 例: AWS Vault / aws-vault で本番書き込みは1時間限定の昇格セッション
aws-vault exec prod-writer-mfa --duration=1h -- \
psql "postgresql://[email protected]/app_prod"
# セッション終了でクレデンシャルは自動失効
エージェントには昇格セッションを渡さない。「AIが書き込みたい」→「人間が昇格セッションで実行」の役割分担を徹底する。
レイヤー②:CLAUDE.md / .cursorrules / AGENTS.md でルールを明文化する
エージェントへのシステムプロンプトはOSSとリポジトリの間で標準化が進んでいる。Claude CodeはCLAUDE.md、CursorはAGENTS.md(または.cursorrules)、Codexは.codexrulesを読み込む。これらに「本番DBに触れない」を明示しておくと、エージェントの初手の判断を縛れる。
<!-- CLAUDE.md / AGENTS.md の禁則例 -->
## 禁則事項(最重要)
- 本番DBへの直接接続を禁止する。`prod`/`production`を含む接続文字列を見つけたら停止し、ユーザーに確認すること
- DELETE / DROP / TRUNCATE / `volumeDelete` / `dropDatabase` などの破壊的SQL・APIは、ユーザーが本セッション内で明示的に依頼した場合のみ実行する
- リポジトリ内で発見したAPIトークンを、その場では絶対に使用しない。トークンの目的をユーザーに確認すること
- 環境変数の不一致やクレデンシャルエラーが出た場合、自分で修復しようとせず、ユーザーに報告すること
- `curl` / `wget` / `httpx` 経由で外部APIを叩く前に、必ず計画と影響範囲を提示し承認を得ること
ただし前節「エージェントの自白」で見たとおり、プロンプト上のルールは確実な防壁にはならない。今回の事件でもCursorのシステムプロンプトには「破壊操作禁止」が含まれていた。CLAUDE.mdは多層防御の一層目として、人間とエージェントの認識合わせの役割を担うものとして位置づける。
CLAUDE.mdの具体的な書き方や運用パターンは CLAUDE.md書き方完全ガイド を、AIエージェントへのルール記述を「ハーネス」として構造化する手法は ハーネスエンジニアリング実装パターン2026 と プロンプトエンジニアリングvsハーネスエンジニアリング に詳しい。本番運用での具体的な設計は ハーネスエンジニアリング本番運用ガイド を参照されたい。
レイヤー③:Claude Codeの.claude/settings.jsonを完全防御モードで構成する
Claude Codeのpermissions設定は、ルールの優先順位とマージ順序が公式に定義されている。プロジェクトのenterprise設定→user設定→ローカル設定の順で読み込まれ、denyはallowより強い。チームでは「企業ポリシーは上書き不可」を活用してエンジニアが個人で緩められない構造にする。
// .claude/settings.json(プロジェクトルートにコミット)
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(npm test:*)",
"Bash(npm run lint:*)",
"Bash(pytest:*)",
"Read(**)"
],
"deny": [
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(httpx:*)",
"Bash(railway:*)",
"Bash(aws:*)",
"Bash(gcloud:*)",
"Bash(kubectl delete:*)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(cat .env*)",
"Bash(cat */secrets/*)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"disallowedTools": ["WebFetch"]
}
Read(./.env) や Read(./.env.*) を deny に入れると、Claude Codeの組み込みReadツールから.envを読む経路を塞げる。ただしRead/Edit の deny ルールはBashのサブプロセスには適用されない点に注意が必要だ。公式ドキュメント(Claude Code 権限ドキュメント)も次のように明記している。
公式ドキュメントの注意書き:「
Read(./.env) deny ルールは Read ツールをブロックしますが、Bash での cat .env は防止しません。」つまり Read(./.env) を deny しても、エージェントが Bash(cat .env) を発行すれば中身を読めてしまう。徹底的にブロックするには、上の例のように Bash(cat .env*) も deny に列挙するか、OSレベルの強制であるClaude Code サンドボックスを併用すること。
公式ドキュメントは「コマンド引数を制約しようとする Bash 権限パターンは脆弱です」と明示している。たとえば
Bash(curl http://github.com/ *) という許可は、curl -X GET http://github.com/...・https://...・リダイレクト・変数経由・余分なスペース等のバリエーションを取りこぼす。さらに Claude Code は &&・||・;・| 等のシェル演算子を認識しているため、Bash(safe-cmd *) という許可は safe-cmd && other-cmd を承認しない。**deny を網羅的に・allow を最小限に**書き、URLフィルタは WebFetch(domain:...) 側に寄せるのが安全。
Claude Codeには全パーミッションチェックを無効化する
--dangerously-skip-permissions(bypassPermissions モード)がある。公式ドキュメントは「Claude Code が損害を引き起こせないコンテナや VM などの隔離された環境でのみ使用してください」と限定している。本番DBや本番インフラのクレデンシャルを保持する開発者の通常端末では使用禁止とし、管理者は管理設定で permissions.disableBypassPermissionsMode を "disable" に設定して**個人設定でも上書き不可**にできる。
複数リポジトリでの一貫性が必要なら、企業の管理設定(macOS: /Library/Application Support/ClaudeCode/managed-settings.json、Windows: C:\ProgramData\ClaudeCode\managed-settings.json、Linux: /etc/claude-code/managed-settings.json)にdenyを集約し、allowManagedPermissionRulesOnly: true を設定すれば、ユーザーやプロジェクト設定での allow/ask/deny 定義そのものを禁止できる。「個人設定でも上書きできない deny」を組織で配布する仕組みが公式に用意されている。
レイヤー④:APM・監査ログでAIエージェントの操作を可視化する
「事故が起きてから気づく」ではなく「異常な操作を即座に検知する」レイヤーが必要だ。AIエージェントは1分間に数十回のシェル・API呼び出しを発行することもあり、人間が事後にログを追うのは現実的ではない。APM(Application Performance Management)と監査ログを組み合わせて、機械的にアラートを上げる。
| 監視項目 | 推奨ツール | アラート条件例 |
|---|---|---|
| シェル/CLI実行 | Datadog Agent / Sysmon / auditd | 1分間に10回超のDB接続コマンド |
| DBクエリ | pgaudit / MySQL Audit Plugin | DELETE文が同一セッションで5回超 |
| クラウドAPI操作 | AWS CloudTrail / GCP Audit Logs | *Delete*系APIの実行 |
| アプリログ | Application Insights / New Relic | 短時間に大量の認可エラー |
| AIエージェント操作 | Datadog LLM Observability / Langfuse | 想定外のツール呼び出し連鎖 |
Azure Monitor(Application Insights)でのアラート設定例:
// Application Insights: 短時間に大量のDELETE/DROPが発行されたら通知
AppRequests
| where TimeGenerated > ago(5m)
| where Name has_any ("DELETE", "DROP", "TRUNCATE", "volumeDelete")
| summarize count() by bin(TimeGenerated, 1m), Name
| where count_ > 5
Datadogでのコマンド実行アラート:
# Datadog Monitor: rmコマンドが本番ホストで実行されたら通知
name: "AI agent ran destructive command on prod"
type: log alert
query: |
logs("env:prod (rm -rf OR \"DROP TABLE\" OR \"TRUNCATE\" OR volumeDelete)").index("main").rollup("count").last("5m") > 0
message: |
本番環境で破壊的コマンドが検出されました。即座に確認してください。
@slack-security-oncall @pagerduty-prod
ポイントは「人間がやろうとAIがやろうと同じアラートで拾う」こと。AIエージェント専用の監視を別建てにすると運用が分裂し、結局見逃される。既存のSRE/SecOpsの仕組みに統合するのが現実的だ。
レイヤー⑤:チーム横断のAIツール利用ガイドラインを策定する
技術対策だけでは限界がある。「何をしてよくて何をしてはいけないか」をチーム全員が同じ理解を持つためのガイドラインを文書化する。最低限カバーすべきは以下の5項目だ。
1. 環境別ポリシー: 開発環境はフル機能、ステージングは書き込み制限、本番は読み取り専用+人間承認のみ。「本番にAIエージェントから直接アクセスしない」を全員のデフォルトに。
2. クレデンシャル管理: Vault/AWS Secrets Manager等の動的シークレットを使用。長期トークンの.envコミット禁止、pre-commit hookでgitleaks等のスキャンを必須化。
3. 破壊的操作の承認フロー: 削除・破棄は必ずPR/Issue/Slack承認を経由。AIエージェントは「提案」までしかできず、最終実行は人間。
4. インシデント報告: AIが意図しない操作をした場合の即時報告ルート(Slack #ai-incidents 等)と、ロールバック手順の事前訓練。
5. ツール選定とアップデート: 利用する AI コーディングツールを明示的に許可リスト化し、設定(CLAUDE.md / settings.json)をテンプレートとしてリポジトリに同梱する。
Vibe Codingの本番運用において組織として何を整えるべきかは Vibe Coding in Prod:Anthropicが語る本番運用の原則 で網羅的に整理されている。CAMPFIRE事件のようにGitHub侵害から本番DBへ波及する経路を塞ぐSecret管理とアカウント分離は CAMPFIRE GitHub侵害から学ぶSecret管理と最小権限設計 と併読されたい。
Git hooks / pre-commitでDB操作を検出する
最後の細工として、コミット前にDB破壊操作のSQLがコードに紛れていないかを機械的に検出する。pre-commitフレームワークで簡単に実装できる。
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: detect-destructive-sql
name: Detect destructive SQL
entry: bash -c '! grep -RInE "(DROP TABLE|TRUNCATE|DELETE FROM .* WHERE 1=1)" --include="*.sql" --include="*.py" --include="*.ts" .'
language: system
pass_filenames: false
- id: detect-railway-token
name: Detect Railway/AWS tokens
entry: bash -c '! grep -RInE "(railway_[a-z0-9]{32,}|AKIA[0-9A-Z]{16})" --exclude-dir=.git --exclude-dir=node_modules .'
language: system
pass_filenames: false
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
hooks:
- id: gitleaks
これらのフックはAIエージェントが生成したコードもコミット時に同じく検査される。「AIが書いたから例外」を作らないのが運用の鉄則だ。
Claude Codeのpermissions設計との比較
CursorとClaude Code、それぞれのAIコーディングツールがどの程度のサンドボックス機能を持つかを整理する。これは「どちらが良い・悪い」ではなく「何をオフで使っているか」を理解するためのチェックリストだ。
| 機能 | Cursor(Agent) | Claude Code |
|---|---|---|
| ツール許可リスト | プラグイン単位(粗い) | allowedTools/disallowedToolsで粒度高 |
| Bashコマンドのワイルドカード制限 | 限定的 | Bash(cmd *)形式で詳細 |
| ファイルシステムスコープ | ワークスペース単位 | additionalDirectoriesで明示 |
| ホストネットワーク隔離 | 既定で開放 | サンドボックス機能で OS レベル強制可 |
| 確認プロンプト | 一括で許可されがち | 1コマンドごと確認・skip可 |
| プランモード(読み取り専用) | あり(限定的) | あり(明確な切り替え) |
| 実行ログの監査性 | エージェントUI内 | ローカルログ+hooks |
Claude Code側が一般に細かい制御を提供しているが、それは「設定すれば」の話だ。多くのチームがpermissionsをデフォルトのまま使っており、Bash系コマンドが包括的に許可されたまま運用されている。今回の事件はCursor固有ではなく、「サンドボックスを設定していないコーディングエージェント全般」に共通する問題として読むのが正しい。
Claude Code permissionsの公式仕様で押さえておく要点
Claude Code 公式ドキュメント(権限を設定する)に基づき、Cursorとの比較に使える要点を整理する。Cursorには2026年4月時点で同等の正式な権限仕様文書が公開されておらず、これがClaude Codeを選ぶ実務的な理由のひとつになる。
1. ルール評価順序:deny → ask → allow
公式ドキュメント直接引用:「ルールは順序で評価されます。deny → ask → allow。最初にマッチしたルールが優先されるため、deny ルールは常に優先されます。」
つまり管理者が deny を1本書けば、ユーザーがどんな allow を足しても上書きできない。これは組織ポリシーを技術的に強制する仕組みとして極めて重要だ。Cursorの設定はチェックリスト形式で「全許可」に近づきがちで、deny優先の概念が明確に文書化されていない。
2. 設定ファイルの優先順位(5レベル)
1. 管理設定(managed-settings.json) ← 最強・他レベルでオーバーライド不可
2. コマンドライン引数(--allowedTools など)
3. ローカルプロジェクト設定(.claude/settings.local.json)
4. 共有プロジェクト設定(.claude/settings.json) ← Gitにコミット
5. ユーザー設定(~/.claude/settings.json)
公式仕様:「管理設定 deny は --allowedTools でオーバーライドできず、--disallowedTools は管理設定が定義する内容を超えて制限を追加できます」。4番(settings.json)はリポジトリにコミットしてチーム共有、3番(settings.local.json)は個人ローカルで.gitignore対象という棲み分けが標準だ。
3. 6つの権限モード
| モード | 説明 | 用途 |
|---|---|---|
default |
各ツール初回使用時に確認 | 通常の対話開発 |
acceptEdits |
ファイル編集と一部FSコマンドを自動承認 | 信頼できる作業中 |
plan |
読み取りのみ・編集と実行は不可 | 計画立案・調査 |
auto |
バックグラウンド安全チェック付き自動承認(研究プレビュー) | 限定的 |
dontAsk |
事前承認されたツール以外は自動拒否 | 厳格な本番調査 |
bypassPermissions |
すべてのプロンプトをスキップ | 隔離環境専用・非推奨(前述) |
plan モードは今回のPocketOSのような事故を完全に防ぐ最強の予防策だ。本番アクセス可能な端末では defaultMode: "plan" を管理設定で強制し、書き込みが必要になったタイミングで明示的にモード切替を行うという運用が考えられる。
4. ルール構文:絶対パス・相対パス・ホームの明示が必要
ファイルパスマッチングはgitignore準拠で、プレフィックスでスコープが完全に変わる点が重要だ。
| パターン | 意味 | 例 |
|---|---|---|
//path |
ファイルシステム絶対パス | Read(//Users/alice/secrets/**) |
~/path |
ホームディレクトリ起点 | Read(~/.aws/credentials) |
/path |
プロジェクトルート相対 | Edit(/src/**/*.ts) |
path または ./path |
カレントディレクトリ相対 | Read(*.env) |
公式の警告:「/Users/alice/file のようなパターンは絶対パスではありません。プロジェクトルートからの相対パスです。絶対パスには //Users/alice/file を使用してください。」初心者が間違えやすいポイントとして明示されている。
5. Bashの読み取り専用組み込み
公式仕様:ls、cat、head、tail、grep、find、wc、diff、stat、du、cd、および git の読み取り専用形式は設定不可能な形で承認なしに実行される。許可リストに書かなくても動く一方で、これらにdenyを追加してプロンプトを要求することは可能。
注意点:複合コマンドで cd と git を組み合わせると、ターゲットディレクトリに関係なく常にプロンプトが表示される。本番環境のリポジトリへの cd && git ... は事実上ブロックされる動作と理解しておく。
6. WebFetch・MCP・Subagentの個別制御
公式ドキュメントに準拠した推奨設定例:
// .claude/settings.json: WebFetch・MCP・Agentの厳格制御
{
"permissions": {
"allow": [
"WebFetch(domain:github.com)",
"WebFetch(domain:pkg.go.dev)",
"WebFetch(domain:docs.python.org)",
"mcp__playwright"
],
"deny": [
"WebFetch",
"mcp__filesystem__write_file",
"Agent(custom-deploy-agent)"
]
}
}
WebFetch を deny に置きつつ特定ドメインを allow で開ける構造を取れる。MCPは mcp__サーバー名__ツール名 の階層で書け、mcp__server__* でサーバー単位の包括許可も可能。
Cursor とのアーキテクチャ的な差分
公式仕様に基づき、両ツールの安全性に効く本質的な差を整理する。
| 観点 | Cursor | Claude Code | 安全性への寄与 |
|---|---|---|---|
| 権限ルールの仕様書 | 非公開・断片的 | 公式ドキュメントに完全公開 | 高(再現性・監査性) |
| deny優先の評価順序 | 未明示 | 公式に deny→ask→allow と明記 | 高(組織ポリシー強制可) |
| 管理設定でのユーザー上書き防止 | なし | allowManagedPermissionRulesOnly: true等で技術的に強制 |
極高(エンタープライズ要件) |
| サンドボックス機能 | なし | 公式機能(/ja/sandboxing) |
高(OS強制) |
| プランモード(読み取り専用切替) | 限定的 | 公式モードとして提供 | 中〜高 |
| バイパスモードの組織側無効化 | 該当機能なし | disableBypassPermissionsMode: "disable" |
高 |
| 設定の優先順位 | 文書化が薄い | 5階層が公式定義 | 高(チーム運用) |
「Cursorは安全機能が無い」のではなく、「Cursorには現状、組織が技術的に強制できる権限モデルの公式仕様が存在しない」のが本質だ。今回のPocketOS事件で「Cursorのシステムプロンプトの破壊操作禁止ルールが機能しなかった」という証言は、システムプロンプトレベルのガードレールに依存していた構造の表れである。Claude Codeは管理設定 + deny優先 + サンドボックスでプロンプトに依存しない多層防御を組める点で、本番アクセスを許す環境での選好理由になる。
詳細はそれぞれのツール解説を参照:
- Claude Code側のサンドボックス・hooks・MCP制御は サプライチェーンセキュリティ完全ガイド2026 で扱う
- AIエージェントのファイル操作の実害290件の分析は AIエージェントが290件のファイル破壊インシデントを起こす理由とYoloFSが示す解法
- 関連するMCP経由の脆弱性は MCP脆弱性:STDIOトランスポートの設計欠陥で20万台のサーバーがRCEの危険に
関連事案との連続性——個別事故ではなく構造問題
過去半年でAIエージェントに関連する大規模事故は連続しており、それぞれが別の層の欠陥を露わにしている。
2025-07"] A --> C["YoloFS研究 290件分析
2026-04"] A --> D["PocketOS事件
2026-04(本記事)"] A --> E["GitHubコメント
プロンプトインジェクション"] B --> B1["コード凍結中の
暴走実行"] C --> C1["シェル経由の
破壊が65%"] D --> D1["広権限トークン
+即時破壊API"] E --> E1["外部入力で
エージェント乗っ取り"] style A fill:#7c3aed,color:#fff
それぞれが指す問題は異なる:
- Replit事件:エージェント自身のセルフコントロール(凍結指示の遵守)の限界
- YoloFS研究:シェルコマンド経由の意図しないファイル破壊が主な実害
- PocketOS事件(本件):API経由の即時破壊と権限設計の同時失敗
- プロンプトインジェクション攻撃:第三者が外部入力経由でエージェントを乗っ取る経路
詳細は GitHubコメント経由でAIエージェントを乗っ取るプロンプトインジェクション攻撃 も参照。これらを横断的に見ると、AIエージェントのセキュリティ問題は「ひとつの強力な防御」では足りないことが分かる。プロンプト・サンドボックス・権限・API・バックアップの5層をすべて設計する多段防御が必要だ。
開発者向けチェックリスト
本記事の対策を実行可能な形にまとめる。リポジトリ単位でこのチェックを通すだけで、PocketOS型の事故の再現可能性は大幅に下がる。
□ リポジトリ全体をシークレットスキャン(gitleaks/trufflehog)し、コミット履歴も検査した
□ 検出されたAPIトークンは即座にローテーションし、用途別・環境別に再発行した
□ 本番に対する破壊権限を持つトークンは、CI・開発端末・リポジトリのいずれにも置いていない
□ インフラプロバイダの「削除保護」「遅延削除」を全本番リソースで有効化した
□ バックアップを別アカウント・別リージョンに分離し、書き込み権限と削除権限を分けた
□ AIエージェントが動作する環境のシェル経由ネットワーク呼び出し(curl/wget等)を制限した
□ 破壊的操作は人間承認ワークフロー経由のみ実行可能とした
□ エージェントの操作ログを永続化し、定期レビュー対象に組み込んだ
まとめ
PocketOS事件は「AIが暴走した」という単純な物語に矮小化すべきではない。事故は広すぎるAPIトークン・確認のない破壊API・同居バックアップの3層が同時に成立して初めて発生した。AIエージェントはきっかけを引いたが、引き金が引けてしまう銃を設計したのは人間とプロバイダ側だ。
防御の核心は新規の魔法的な技術ではない。最小権限の徹底・破壊操作の人間確認・バックアップの隔離という、伝統的なシステム運用の基本そのものだ。AIエージェントを安全に本番に近づけるためには、エージェントを賢くする以上に、エージェントが扱う環境を「失敗してもいい場所」にする設計が問われている。
サプライチェーン全体での防御策と最小権限の実装パターンは サプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリスト でまとめている。あわせて参照してほしい。
参照ソース
一次・公式ドキュメント
事件報道
- Claude-powered AI coding agent deletes entire company database in 9 seconds — Tom’s Hardware
- Cursor-Opus agent snuffs out startup’s production database — The Register
- 9 seconds: a Cursor agent deleted a production database while quoting its own destructive-actions rule — DEV Community
- “It took 9 seconds”: AI agent running on Anthropic’s Claude Opus 4.6 wipes critical database — BusinessToday
- AI agent confesses to completely destroying the production environment database and backups — GIGAZINE
- Cursor AI Agent Deletes Startup Database in Seconds — Let’s Data Science
- Claude-powered AI coding agent deletes entire company database in 9 seconds — OODAloop
- Vibe coding service Replit deleted production database — The Register(参考:2025年Replit事件)