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など他ツールのパーミッション設計との比較を中立的にまとめる。

結論ファースト:本記事で押さえる5つのポイント
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か月前」だった。

flowchart LR A["Cursor + Claude
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を使う場合はpermissionsallow/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設定→ローカル設定の順で読み込まれ、denyallowより強い。チームでは「企業ポリシーは上書き不可」を活用してエンジニアが個人で緩められない構造にする。

// .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/Edit deny ルールは Bash サブプロセスには適用されない
公式ドキュメントの注意書き:「Read(./.env) deny ルールは Read ツールをブロックしますが、Bash での cat .env は防止しません。」つまり Read(./.env) を deny しても、エージェントが Bash(cat .env) を発行すれば中身を読めてしまう。徹底的にブロックするには、上の例のように Bash(cat .env*) も deny に列挙するか、OSレベルの強制であるClaude Code サンドボックスを併用すること。

Bash 引数を制約するパターンは脆弱——複合コマンドにも気をつける
公式ドキュメントは「コマンド引数を制約しようとする 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:...) 側に寄せるのが安全。

–dangerously-skip-permissionsは本番アクセスのある端末では絶対に使わない
Claude Codeには全パーミッションチェックを無効化する --dangerously-skip-permissionsbypassPermissions モード)がある。公式ドキュメントは「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項目だ。

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の読み取り専用組み込み

公式仕様:lscatheadtailgrepfindwcdiffstatducd、および git の読み取り専用形式は設定不可能な形で承認なしに実行される。許可リストに書かなくても動く一方で、これらにdenyを追加してプロンプトを要求することは可能。

注意点:複合コマンドで cdgit を組み合わせると、ターゲットディレクトリに関係なく常にプロンプトが表示される。本番環境のリポジトリへの 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)"
    ]
  }
}

WebFetchdeny に置きつつ特定ドメインを 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サンドボックス——OSレベル強制で本番を物理的に届かなくする

permissionsはアプリケーションレベルのガードだが、Claude CodeにはさらにOSレベルでBashサブプロセスを隔離する公式サンドボックス機能が用意されている。今回のPocketOS事件のように「エージェントがリポジトリ内でAPIトークンを発見し、curlで本番APIを直撃する」という攻撃経路をそもそも経路ごと存在させないためのレイヤーだ。

公式仕様:Claude Code サンドボックス(公式ドキュメント)。本節では公式仕様に基づきPocketOS事件への適用可能性を分析する。

サンドボックスの仕組み——macOS Seatbelt / Linux bubblewrap / プロキシ

サンドボックスはファイルシステム分離とネットワーク分離の両方をOSプリミティブで強制する仕組みだ。プラットフォームごとの実装は次のとおり。

プラットフォーム 実装 必要パッケージ
macOS Seatbelt(組み込み) 不要・追加インストールなし
Linux bubblewrap bubblewrap socat
WSL2 bubblewrap bubblewrap socat
WSL1 非対応
Windows ネイティブ 計画中(2026-04時点)

公式の警告引用:「効果的なサンドボックス化には、ファイルシステムとネットワークの両方の分離が必要です。ネットワーク分離がない場合、侵害されたエージェントは SSH キーなどの機密ファイルを流出させる可能性があります。ファイルシステム分離がない場合、侵害されたエージェントはシステムリソースにバックドアを仕掛けてネットワークアクセスを取得する可能性があります。」片方だけ有効にしても抜け穴になる点が公式仕様で明示されている。

ファイルシステムは「現在の作業ディレクトリのみ書き込み可・コンピュータ全体は原則読み取り可」がデフォルト動作で、sandbox.filesystem.allowWrite / denyRead などで明示的に絞る。ネットワークはサンドボックス外で動くプロキシサーバを経由し、allowedDomains で承認したドメインだけが通る。

PocketOS事件はサンドボックスで防げたか——部分的にYES、完全にはNO

率直な分析として、Claude Code + 適切なサンドボックス設定であれば事件の経路は塞げた可能性が高い。ただし「サンドボックスを入れさえすれば安全」という単純な話ではない。

サンドボックスがPocketOS型事件に効く条件と効かない条件
効く(防げた): Railwayの管理APIドメイン(backboard.railway.app)が allowedDomains に含まれていなければ、curl 経由の volumeDelete リクエストはOSレベルで弾かれる。プロンプト経由のガードと違い、「忘れた」「無視した」が起こらない。
効かない(防げない): 同じドメインを日常的なデプロイで allowedDomains に入れている場合、本番権限を持つトークンと組み合わさればサンドボックスは透過する。サンドボックスは「到達できるか」を制御するが「到達した先で何ができるか」は制御しない。

つまりサンドボックスは前節までの「権限分離」「Read Only運用」「人間承認ワークフロー」と必ず併用するのが正しい設計だ。公式ドキュメントも「サンドボックス化と許可は、一緒に動作する補完的なセキュリティレイヤー」と明記している。

防御レイヤー 何を制御するか PocketOS事件への効果
permissions(許可ルール) エージェントがどのツールを呼べるか Bash(curl:*) deny で防げる(プロンプトレベル)
サンドボックス(OS強制) Bashが何にアクセスできるか 未許可ドメインのcurlをOSが拒否(強制レベル)
トークン権限分離 仮にAPIに到達しても何ができるか Read Onlyトークンなら破壊不可
人間承認ワークフロー 破壊操作の最終ゲート volumeDeleteを人間レビュー経由のみに

サンドボックス設定例——settings.jsonの実装パターン

公式仕様に準拠した、本番アクセス事故予防に効く .claude/settings.json の構成を示す。

パターン①:開発作業向け・本番ドメインを明示的に拒否

// .claude/settings.json: 開発作業を sandbox 内に閉じ込める
{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "filesystem": {
      "allowWrite": ["./", "~/.cache/npm"],
      "denyRead": ["~/.aws", "~/.ssh", "~/.kube", "~/.config/gh"]
    },
    "network": {
      "allowedDomains": [
        "registry.npmjs.org",
        "pypi.org",
        "files.pythonhosted.org",
        "github.com",
        "api.github.com"
      ],
      "deniedDomains": [
        "backboard.railway.app",
        "*.railway.app",
        "*.amazonaws.com",
        "console.cloud.google.com"
      ]
    }
  },
  "permissions": {
    "deny": [
      "Bash(railway:*)",
      "Bash(aws:*)",
      "Bash(gcloud:*)"
    ]
  }
}

ポイント:

  • failIfUnavailable: trueサンドボックスが起動できない環境ではClaude Code自体が起動しない。サンドボックス未対応のWSL1や依存関係未インストール時にうっかり「ノーガード運用」に落ちることを防ぐ
  • denyRead~/.aws ~/.ssh ~/.kube を入れることで、仮にエージェントが資格情報を探しても物理的に読めない
  • deniedDomains でRailway・AWS・GCPの管理コンソール系を遮断。allowedDomains を狭く保ち、本番インフラ系は全て denied 側に
  • permissions.denysandbox.network.deniedDomains両方書く(permissionsはアプリレベル、deniedDomainsはOSレベル、片方が抜けても他方が止める)

パターン②:本番資格情報が物理的に存在しないコンテナで起動

開発者の通常端末ではなく、docker compose本番資格情報が一切ない隔離コンテナを立て、その中でClaude Codeを起動する。サンドボックスをコンテナ内で動かす場合、Linux実装は特権のないユーザー名前空間を必要とするため、Dockerホスト側で --security-opt seccomp=unconfined などの調整が要る。公式ドキュメントは「enableWeakerNestedSandbox モードはセキュリティを大幅に弱める」と警告しているため、Dockerでのネストはサンドボックス未対応のフォールバックではなく追加の隔離層として位置づける。

# docker-compose.yml: AIエージェント専用の隔離開発環境
services:
  agent-shell:
    image: node:22-bookworm
    user: "1000:1000"
    working_dir: /workspace
    environment:
      # 本番系の環境変数は一切注入しない
      ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
      # 開発DBのみ
      DATABASE_URL: ${DEV_DATABASE_URL}
    volumes:
      - ./:/workspace:rw
      # 本番系の認証情報は明示的にマウントしない
      # ~/.aws ~/.ssh ~/.kube は持ち込まない
    cap_drop: [ALL]
    security_opt:
      - no-new-privileges:true
    networks: [agent-net]
    command: |
      bash -c "
        apt-get update && apt-get install -y bubblewrap socat &&
        npm install -g @anthropic-ai/claude-code &&
        claude
      "

networks:
  agent-net:
    driver: bridge
    # 必要なら独自プロキシで egress を制御

このコンテナ内では ~/.aws/credentials も Railway CLI トークンも物理的に存在しないため、PocketOS型の「リポジトリスキャン → トークン発見 → 本番削除」の経路は最初の一歩から不可能になる。Claude Codeのサンドボックスはコンテナ内でさらにbubblewrapで二重に隔離する形になる。

パターン③:エンタープライズ管理設定で組織全体に強制

組織のAIツール管理者は、管理設定(macOS: /Library/Application Support/ClaudeCode/managed-settings.json、Linux: /etc/claude-code/managed-settings.json)で個人が上書きできないサンドボックスポリシーを配布できる。

// /etc/claude-code/managed-settings.json: 組織配布の強制ポリシー
{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": ["~/.aws", "~/.ssh", "~/.kube", "~/.gnupg"],
      "allowManagedReadPathsOnly": true
    },
    "network": {
      "allowManagedDomainsOnly": true,
      "allowedDomains": [
        "registry.npmjs.org",
        "pypi.org",
        "github.com",
        "api.github.com"
      ],
      "deniedDomains": [
        "*.railway.app",
        "*.amazonaws.com",
        "*.googleapis.com"
      ]
    }
  },
  "permissions": {
    "disableBypassPermissionsMode": "disable"
  }
}

ポイント:

  • allowUnsandboxedCommands: falsedangerouslyDisableSandbox エスケープハッチ自体を無効化。エージェントが「サンドボックス外で実行したい」と判断してもユーザー承認画面そのものが出ない
  • allowManagedDomainsOnly: true管理設定の allowedDomains 以外は全て自動拒否。個人が ~/.claude/settings.json でドメインを足しても無視される
  • disableBypassPermissionsMode: "disable" でbypassPermissionsモード(旧 --dangerously-skip-permissions)を個人設定でも有効化不可にする

「本番にアクセスさせない」サンドボックス設計の4パターン

PocketOS型事件を構造的に防ぐためのサンドボックス設計を、影響範囲・適用難易度別に整理する。

設計パターン 仕組み 効果 適用コスト
① ドメイン拒否型 本番管理APIドメインを deniedDomains に列挙 中(既知ドメインのみ) 低(既存環境に追加)
② 許可ホワイトリスト型 allowManagedDomainsOnly: true + 開発系のみallow 高(明示許可以外全て遮断) 中(運用テスト要)
③ 隔離コンテナ型 Docker内でサンドボックス、本番資格情報なし 高(資格情報物理不在) 高(環境構築・配布)
④ devcontainer型 VS Code dev containers + sandbox連携 高(コードと環境が一体化) 中〜高(チーム標準化要)

公式が npx @anthropic-ai/sandbox-runtime <command> というOSSサンドボックスランタイムも提供しており、Claude Code以外のエージェントやMCPサーバを同じ仕組みで隔離できる(GitHub: anthropic-experimental/sandbox-runtime)。組織内製のAIワークフロー全体に同じ境界を適用する道が公式に開かれている。

サンドボックスにも限界がある——broad allowedDomainsとUnixソケットに注意
公式ドキュメントは github.com のような広いドメインを許可することで生じるデータ流出リスクと、ドメインフロンティングによるネットワークフィルタ回避の可能性を明示している。さらに allowUnixSockets/var/run/docker.sock を許可するとサンドボックス境界が事実上無効化されるため、Unixソケット許可は厳格に審査する。サンドボックスは完全な防壁ではなく、深層防御の一層という位置づけを忘れない。

サンドボックス導入チェックリスト

本番アクセス端末でClaude Codeサンドボックスを導入する手順
macOS / Linux(WSL2) のいずれかであることを確認(WSL1とWindowsネイティブは現状非対応)
Linux/WSL2 では bubblewrapsocat をインストール
`/sandbox` コマンドでサンドボックスを有効化、自動許可モードで運用テスト
プロジェクトの .claude/settings.jsonsandbox.enabled: true + failIfUnavailable: true を追加
denyRead~/.aws ~/.ssh ~/.kube 等の認証情報ディレクトリを列挙
deniedDomains に本番管理APIドメイン(Railway、AWSコンソール、GCPコンソール等)を列挙
組織配布の場合は管理設定で allowManagedDomainsOnly: trueallowUnsandboxedCommands: false を強制
本番資格情報を保持する端末では Docker / devcontainer による追加隔離を検討
1週間運用してログを確認、ブロックされた正当なアクセスを allowedDomains に追加調整

サンドボックスはサンドボックス単体で完結するセキュリティ施策ではなく、permissions / トークン分離 / 監査ログ / 人間承認との組み合わせで効く。前節までの対策と本節を全て同時に適用するのが正しい設計だ。


関連事案との連続性——個別事故ではなく構造問題

過去半年でAIエージェントに関連する大規模事故は連続しており、それぞれが別の層の欠陥を露わにしている。

flowchart TB A["AIエージェントの本番事故"] A --> B["Replit / SaaStr事件
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型の事故の再現可能性は大幅に下がる。

AIエージェント運用前のセキュリティチェックリスト
リポジトリ全体をシークレットスキャン(gitleaks/trufflehog)し、コミット履歴も検査した
検出されたAPIトークンは即座にローテーションし、用途別・環境別に再発行した
本番に対する破壊権限を持つトークンは、CI・開発端末・リポジトリのいずれにも置いていない
インフラプロバイダの「削除保護」「遅延削除」を全本番リソースで有効化した
バックアップを別アカウント・別リージョンに分離し、書き込み権限と削除権限を分けた
AIエージェントが動作する環境のシェル経由ネットワーク呼び出し(curl/wget等)を制限した
破壊的操作は人間承認ワークフロー経由のみ実行可能とした
エージェントの操作ログを永続化し、定期レビュー対象に組み込んだ

まとめ

PocketOS事件は「AIが暴走した」という単純な物語に矮小化すべきではない。事故は広すぎるAPIトークン・確認のない破壊API・同居バックアップの3層が同時に成立して初めて発生した。AIエージェントはきっかけを引いたが、引き金が引けてしまう銃を設計したのは人間とプロバイダ側だ。

防御の核心は新規の魔法的な技術ではない。最小権限の徹底・破壊操作の人間確認・バックアップの隔離という、伝統的なシステム運用の基本そのものだ。AIエージェントを安全に本番に近づけるためには、エージェントを賢くする以上に、エージェントが扱う環境を「失敗してもいい場所」にする設計が問われている。

サプライチェーン全体での防御策と最小権限の実装パターンは サプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリスト でまとめている。あわせて参照してほしい。


参照ソース

一次・公式ドキュメント

事件報道