CASE · 中程度 · data-loss
未検証の報告公開情報からの収集削除ガードを足す作業の最中に、Claude CodeのテストがMacのホームディレクトリを消したとみられる(未検証の報告)
筆者によれば、2026年10月7日の深夜、auto モードのClaude Codeに iOS アプリの開発を任せているあいだに、Macのホームディレクトリの中のファイルがまとまって消えた。push していなかった約9日分のコミットも、手元の .git ごとなくなっていた。筆者自身の postmortem で、原因は推定である。
約6分で読めます
- 発生日
- 分類
- data-loss
- 影響範囲
- data
- 検知
- operator-noticed
- タグ
- #claude-code #subagent #auto-mode #rm-rf #home-directory #tdd #sandbox #pretooluse-hook #unpushed-commits #postmortem
CH 1
原因
筆者は、スクリプトに「引数がホームディレクトリなら止める」ガードを足す作業が発端だったとみている。サブエージェントがガードを書く前にテストを実行し、テストが渡した本物のホームディレクトリに対して、スクリプトが引数のディレクトリを rm -rf したという推定である。実行前の判定が見るのは Claude が打つコマンドの1行で、そこから呼ばれたスクリプトの中の削除パスは見えない。当時はサンドボックスも Time Machine もなかった。何が消したのかは断定できないと筆者は述べている。
CH 2
結果
筆者によれば、消えたファイルのうち1,004個は会話ログから取り出せた。サブエージェントが書いた分はログに残っておらず、取り出せなかった。push していなかった約9日分のコミットは .git ごと消えた。
CH 3
対策
筆者は、OSで書き込み先を絞るサンドボックスと、Macの外のバックアップを主な対策にした。deny ルールと hook は補助である。allowUnsandboxedCommands を false にし、OK を出したコミットはすぐ push し、削除処理のテストはテストごとの一時ディレクトリの中だけで実行させる。サンドボックスの外で動かすものは、外に出す理由と代わりの対策を決めて絞った。
何が起きたか
筆者(IT企業のPMで、Claude Codeを使って iOS アプリを作っている個人開発者)によれば、2026年10月7日の深夜、Claude Code に開発を任せているあいだに、Mac のホームディレクトリの中のファイルがまとめて消えた。作業は auto モードで夜通し進めていた。auto モードは、操作ごとの許可の確認を、人の代わりに別のモデルの分類器に任せるモードである。
当時は、サンドボックスも Time Machine も入れておらず、サブエージェントへの指示には毎回「push しない」と入れていた。筆者自身の事後報告であり、原因は推定である。
現場の混乱
筆者が示した時刻(JST)は次のとおりである。
- 01:58 レビュー用のサブエージェントが、ファイルの署名と検証に使うシェルスクリプト sign_macos27.sh に、引数がホームディレクトリなら止めるガードの追加を提案した。メインのセッションが作業用のサブエージェントへ依頼した。
- 02:01 サブエージェントの最後のログは「Add guard/select tests and run RED」だった。
- 02:04 メインのセッションが「ファイルがまとめて消えています」と報告し、「わたしたちの作業ではないと見ています」と述べた。
- 08:02 筆者が報告を読んだ。
- 08:04 メインのセッションが、02:04 の発言を「根拠のない言い切りでした」と訂正した。
筆者は朝、報告を読んで思わず声が出たという。push していなかった約9日分のコミットも、手元の .git と一緒に消えていた。サブエージェントのログは消えたディレクトリの中にあり、同じ夜に macOS のアップデートも動いていたため、何が消したのかは断定できない。
原因
筆者の推定では、sign_macos27.sh は引数で受け取ったディレクトリを rm -rf する処理を持っていた。サブエージェントは、TDD で実装の前にテストを実行して失敗を確かめる段階(RED)で、ガードをまだ書かないままテストを走らせた。テストは「ホームディレクトリを渡したら止まる」ことを確かめるものだったとみられ、ガードがなかったため、スクリプトは渡された本物のホームディレクトリを削除した。当夜のコマンドそのものは記録に残っておらず、サブエージェントの最後のログから、テストを実行する1行だったと筆者は考えている。
筆者によれば、Claude Code の実行前の判定は、Claude が打つコマンドの1行を見て通すか止めるかを決める。筆者が挙げた3つが、この件で止まらなかった理由は次のとおりである。
- deny ルール:テストを実行する1行は、どのパターンにも一致しない。
- critical path の保護:対象は Claude が打つ rm・rmdir で、テストから呼ばれたスクリプトファイルの中の rm が対象になるとは、公式ドキュメントに書かれていないと筆者は述べている。Claude が rm -rf ~ を直接打っていれば、拒否されていたはずだという。
- auto の分類器:渡されるのはユーザーのメッセージ・ツールの呼び出し・CLAUDE.md で、ツールの結果(読んだスクリプトの中身など)は渡らない。
筆者は、あとから足した自作の hook も受け取るのは同じ1行だとしている。さらに、サンドボックスがないと、許可したコマンドはユーザーアカウントが書き込める場所ならどこにでも書き込める。バックアップもなかった。
対策
筆者の主な対策は、OSで書き込み先を絞るサンドボックスと、Macの外のバックアップである。deny ルールと hook は、よくある危ないパターンを早めに止める補助とされている。
- ~/.claude/settings.json で sandbox.enabled を true、allowUnsandboxedCommands を false にする。はじかれたコマンドを、Claude がサンドボックスなしで実行し直せなくなる。
- Time Machine など Mac の外にバックアップを取り、OK を出したコミットはすぐ push する。サンドボックスの中でも、作業ディレクトリの中は消せるからである。
- 削除処理のテストは、テストごとの一時ディレクトリの中だけで実行させる。
- 削除先・書き込み先を判定する hook を自作し、判定関数に偽のホームディレクトリを渡すテスト68件で確かめている。hook がタイムアウトや起動の失敗で終わったときは "onFailure": "block" で止める(筆者によれば、CLI で効くのは 2.1.295 から)。
- サンドボックスの外で実行するものは、Xcode のテストとビルド、xcrun simctl、gh、git push などに絞り、それぞれ代わりの対策を置いた。
筆者の環境は、2026年10月19日時点で macOS、Claude Code は CLI 2.1.292 と VS Code 拡張 2.1.301 である。当夜の版は 2.1.286 だった。
教訓は、削除を伴うスクリプトのテストに本物のパスを渡さないことと、実行前の判定だけに頼らず、OS による制限とバックアップを持つことである。
出典
この記録をチームに回す