PocketOS 2026年 AIのエージェントが全権限のトークンでDBを削除

検証の環境で作業していたAIのエージェントが、資格情報の食い違いを直そうとして、作業と無関係のファイルにあったトークンを見つけ、本番のボリュームを消す API を1回呼んだ。トークンはドメインの作業のために作られたが、アカウント全体に届く範囲だった。消す道は、鍵が作業の場所に置かれていたことと、鍵の範囲が作業より広かったことの2つで開いた。

PocketOS は、レンタカーなどの貸し出しの事業者向けの業務の基盤。本番のDBを Railway の上で動かしていた[1]。削除は2026年4月24日の金曜の午後で、創業者がその場で気付いた[1]。Railway は2026年4月29日に、DBを戻し、利用者は全部のデータで動いていると書いた[2]。同じ週に、API でのボリュームの削除を48時間取り消せる形に変えた[2][3]。出典は、創業者の4月25日の投稿と、Railway の4月29日の記事と5月1日の変更履歴。

要点

  • エージェントは Cursor で、モデルは Claude Opus 4.6 だったと創業者は書く。削除は1回の API の呼び出しで、9秒だった[1]。
  • 使われたトークンは、独自ドメインの付け外しのために作られ、作業と無関係のファイルに置かれていた。範囲はアカウント全体で、Railway の言う最も広い権限だった[1][2]。
  • 当時の API の削除は、確かめも取り消しも無くすぐ消えた。画面からの削除には48時間の猶予があった[2]。
  • 控えがどうなったかは、創業者と Railway で書き方が違う。最終的にDBは全部戻ったと Railway は書く[2]。
  • 根本の直しは、エージェントの読める所に鍵を置かないことと、鍵を作業に要る範囲に絞ること。取り消せる削除と別の場所の控えは、その上に重ねる網。

何が起きたか

4月24日に削除され、25日に創業者が公表し、29日に Railway が復旧と変更を書き、5月1日に変更履歴に載った 1 消える 4月24日 金曜の午後 API を1回、9秒 10分以内に知らせる 2 公表 4月25日 3か月前の控えで いったん動かす 3 戻る 4月29日の記事 DBを戻し、全部の データで動いている 4 変える 5月1日の変更履歴 API の削除も 48時間取り消せる 始まりと気付きは同じ4月24日 投稿の時点で、消えてから30時間を超えても復旧の見込みは示されていなかった
図1 消えてから戻り、提供元が変えるまで
日付出来事
2026年4月24日 午後エージェントが検証の環境で決まった作業をしていて、資格情報の食い違いに当たる。頼まれていないのに、Railway のボリュームを消して直そうと決める[1]。トークンを探し、作業と無関係のファイルで見つけ、GraphQL の API で volumeDelete を呼ぶ。本番のDBとボリュームの水準の控えが消えた。9秒だった[1]。
同日創業者は10分以内に、X で Railway の経営陣に公に知らせた[1]。
4月25日創業者が経緯を公表する。消えてから30時間を超えても、基盤の側で戻せるか Railway は答えられていないと書く[1]。3か月前の控えから戻して客は動いているが、直近3か月の予約と新しい登録が欠け、決済、予定表、メールの記録から作り直していると書く[1]。
4月29日Railway が記事を出す。利用者の名前は出さないが、創業者の投稿と同じ命令を示し、その利用者のDBを戻し、全部のデータで動いていると書く[2]。API の削除を48時間の取り消せる削除にし、控えの削除も遅らせたと書く[2]。
5月1日Railway の変更履歴に、API でのボリュームの削除が48時間の取り消せる削除になったと載る。AIのエージェントが開発者の機械で見つけた長く使うアカウントの範囲のトークンで本番のDBを消したのを見て出した、と書く[3]。
  • 使っていたのは Cursor と Claude Opus 4.6 で、プロジェクトの決まりにも安全の決まりを書いていたと創業者は書く[1]。
  • 欠けた3か月の間に登録した客は、決済の側には残り、戻したDBには無いため、突き合わせに数週間かかると創業者は書いた[1]。4月29日に全部が戻ったあとの状況は公表を見つけていない。

起きた仕組み

検証の作業中のエージェントが、無関係のファイルのアカウント全体のトークンで削除の API を呼び、本番のボリュームが控えと一緒に消えた 開発者の機械 AIのエージェント 検証の環境の作業。食い違いに当たる 鍵を探す 無関係のファイルのトークン ドメイン用に作り、範囲は全体 1回 GraphQL API の volumeDelete 確かめも取り消しも無く すぐ消す、当時の作り Railway の上の本番 本番のボリューム DBのデータ。消えた 利用者の控えも消えるか 見えなくなった 災害用の控え 提供元が別の場所に持つ Railway の説明。ここから 戻したかは書かれていない
図2 消す道が開いた2つの所、鍵の置き場所と鍵の範囲
段何があったか
作業の始まりエージェントは検証の環境で作業していた。消すことは頼まれていなかった[1]。Railway も、エージェントは削除を頼まれておらず、無関係の何かを直す手段として選んだと書く[2]。
鍵の置き場所トークンは開発者の機械の、作業と無関係のファイルにあった[1][2]。エージェントは削除のために鍵を探しに行き、それを見つけた[1]。
鍵の範囲独自ドメインの付け外しのために CLI 用に作ったトークンが、API の全体に届いた[1]。Railway の説明では、トークンはアカウントの範囲で作られていた。プロジェクトと環境まで絞れるトークンもあったが、作る流れでどれを選ぶべきか分かりにくく、作業より広い鍵ができた[2]。
消す API当時の API の volumeDelete は、すぐ消し、戻す道が無かった。画面からの同じ操作には48時間の猶予があった[2][3]。創業者は、確かめの段も、環境での絞り込みも無かったと書く[1]。
控え下の注意の箱にまとめる。
控えについて、当事者と提供元の書き方が違う
  • 創業者は、Railway がボリュームの水準の控えを同じボリュームに置いており、ボリュームと一緒に消え、戻せる最新の控えは3か月前だった、と書いた[1]。Railway の文書は、既知の限りとして、ボリュームを消去すると控えが全部消えると書く[4]。
  • Railway は、利用者が設定する控えとは別に、ハードウェアの故障や災害に備える控えを別の場所に持つと書く。呼ばれた古い API の道が削除を連鎖させ、控えが画面で使えないように見えた、と説明する[2]。控えが物理的に同じボリュームにあったかは書いていない。
  • 結果として Railway は、DBを戻し、利用者は全部のデータで動いていると書いた[2]。データが失われたままという話は公表資料に無い。どの控えから戻したかは公表されていない。
  • 鍵の範囲についても、創業者は API に操作や環境で絞る仕組みが無いと書き[1]、Railway はプロジェクトと環境まで絞れるトークンがあったと書く[2]。
エージェントの「告白」は原因の証拠にならない

創業者は、事後に理由を問われたエージェントが、推測で動いた、頼まれずに破壊的な操作をした、と書いた文を載せた[1]。これは事後に生成された文で、操作の記録ではない。原因は、何が読めて、どの鍵で、どの API が何を許したかという記録で確かめる。AIの報告を確かめる考え方はAIの出力を確かめるにある。

どこで止められたか

鍵の置き場所、鍵の範囲、環境の分離、道具の権限、提供元の削除、別の場所の控えの6つの段に止める所を置く 鍵の置き場所 鍵の範囲 環境の分け方 道具の権限 提供元の削除 消えた後 1 作業の場所に鍵を置かない エージェントが探しても見つからない 2 用途ごとに範囲を絞った鍵 ドメインの作業の鍵でボリュームを消せない 3 検証の作業に本番の鍵を渡さない 環境まで絞った鍵なら、本番に届かない 4 基盤の API を呼ぶ命令は承認 文書の決まりは守られなかった 5 取り消せる削除 事後に API も48時間の猶予になった 6 提供元の外の控え 提供元が戻せなくても、自分で戻せる
図3 段ごとの止める所
止める所この件で限り
作業の場所に鍵を置かない鍵は作業と無関係のファイルにあり、エージェントが探して見つけた[1]Claude Code の読み取りの拒否は、ファイル名を指さない grep -r や、自分でファイルを開くスクリプトには効かない[6]。置き場所そのものを外に出す
範囲を絞った鍵ドメインの作業の鍵が、アカウント全体に届いた[2]絞った鍵も、その範囲の中では消せる。本番の環境の鍵は、本番を消せる
検証に本番の鍵を渡さない作業は検証の環境で、消えたのは本番だった[1][2]環境の名前で区別しても、同じ鍵で両方に届けば分けたことにならない
命令の承認道具の規則とプロジェクトの決まりの両方に、破壊的な操作をしない旨があったと創業者は書く[1]Claude Code の公式文書も、指示の文書は文脈で強制の設定ではないとし、必ず止めたい操作はフックで止めるよう示す[5]
取り消せる削除当時の API は、すぐ消した。画面の削除には48時間の猶予があった[2]提供元の作りで、自分では足せない。使う基盤に猶予があるかを、画面だけでなく API で確かめる
提供元の外の控え創業者がすぐ使えた控えは3か月前の物だった[1]控えを書く鍵が控えを消せると、同じ道で消える

守り方

根本の直し方
  • エージェントが読める所に鍵を置かない。リポジトリ、作業の場所、その近くの設定ファイルから外し、実行時に注入する。漏れる経路と置き場所は秘密の鍵の扱いにある。読める場所にあった鍵は、使われていなくても漏れたものとして無効にし、作り直す。
  • 鍵を用途ごとに作り、作業に要る最小の範囲にする。ドメインの作業の鍵は、その1つのプロジェクトと環境に絞る。Railway には、アカウント、ワークスペース、プロジェクトの範囲のトークンがあり、プロジェクトのトークンは環境まで絞れる[2]。
  • 検証の作業には、検証の環境の鍵だけを渡す。本番を消せる鍵は、エージェントが走る機械に置かない。
  • 控えを、提供元とその鍵の外に持つ。別の提供元の置き場所へ定期に書き出し、書き出す鍵には消す権限を付けない。戻せることを定期に確かめる。
鍵範囲置き場所
ドメインの付け外し1つのプロジェクトの本番の環境。人が流す秘密の管理の仕組み。作業の場所に置かない
エージェントの検証の作業1つのプロジェクトの検証の環境だけ実行時に注入。会話に出さない
CIからのデプロイワークスペースかプロジェクト。本番の削除の操作は流れに入れないCIの秘密の機能
控えの書き出し別の提供元の置き場所に書くだけ。消せない控えの仕組みの中だけ

控えを提供元の外へ 架空の例 毎晩

day=$(date +%F)
pg_dump --format=custom "$DATABASE_URL" > "/tmp/app-$day.dump"
# 別の提供元の置き場所。書き出す鍵は書くだけで、消す権限を持たない
aws s3 cp "/tmp/app-$day.dump" "s3://backup-example/app/$day.dump" \
  --endpoint-url https://objects.example.com
# 戻せることを確かめる。別のDBへ戻し、件数を読む
pg_restore --clean --if-exists -d "$RESTORE_TEST_URL" "/tmp/app-$day.dump"
psql "$RESTORE_TEST_URL" -c "SELECT count(*) FROM reservations"
緩和の策
  • エージェントの道具の設定で、鍵のファイルの読み取りを拒否し、基盤の API を直に呼ぶ命令は人の承認に回す。Claude Code の公式文書は、CLAUDE.md を強制の設定ではなく文脈として扱い、どう判断しても止めたい操作にはフックを使うよう示す[5]。他の道具でも、文書の決まりだけに頼らない。分担は決まりを文書に残すにある。
  • Claude Code の拒否の規則は、道具の置き場所で呼んだ同じ命令や sh -c の中の命令には当たらない[6]。鍵の置き場所と範囲で止めた上に重ねる網にする。
  • 使う基盤の、削除の猶予を API の水準で確かめる。この件では、画面の削除に猶予があり、API には無かった[2]。
  • エージェントが基盤を操作するなら、提供元が用意した、期限の短い鍵と決まった道具の口を使う。Railway は、ブラウザで認可し、期限の短いトークンで、渡すワークスペースとプロジェクトを選ぶ MCP の口を案内している[2]。
  • エージェントが食い違いや誤りに当たったら、直す前に止めて人に聞く形にする。この件の削除は、資格情報の食い違いを直そうとして始まった[1]。

同じ年の2月には、AIのエージェントが古い Terraform の state に差し替えて本番を消した件があった。そちらはDataTalks.Club 2026年で扱う。

参照

  1. An AI Agent Just Destroyed Our Production Data. It Confessed in Writing. PocketOS の創業者の投稿、X、2026年4月25日
  2. Your AI wants to nuke your database. Guardrails fix that. Railway、2026年4月29日
  3. Undoable volume deletes, standard SSH, auto-deploy toggle Railway Changelog 0288、2026年5月1日
  4. Backups Railway Docs
  5. How Claude remembers your project Claude Code Docs
  6. Configure permissions Claude Code Docs