Tips & Tricks (更新: 2026/6/3)

Claude Code セキュリティ失敗事例7選: 原因・復旧・再発防止

Claude Codeの.env漏洩、本番DB破壊、CI暴走を失敗事例から防ぐ実践ガイド。

Claude Code セキュリティ失敗事例7選: 原因・復旧・再発防止

Claude Code は「コードを書いてくれるチャット」ではなく、ファイルを書き換え、テストを走らせ、Git やデプロイコマンドまで提案できる開発エージェントです。便利な反面、承認ボタンを流れ作業で押すと、人間が手で打ったときと同じ事故が高速に起きます。

この記事では、Masa が小さな検証リポジトリで再現した失敗パターンをもとに、Claude Code のセキュリティ事故を7つに分けて整理します。初心者向けに言うと、permissions は「やってよい操作の境界」、hook は「実行直前に止める検問」、sandbox は「壊してもよい作業部屋」です。抽象論ではなく、コピペで使える settings.json、Node.js の検査スクリプト、GitHub Actions の設定まで載せます。

flowchart TD
  Request["User request"] --> Plan["Claude Code plan"]
  Plan --> Permission["Permission rules"]
  Permission --> Hook["PreToolUse hook"]
  Hook --> Execute["Tool execution"]
  Execute --> Audit["Log, review, recovery"]
  Hook -->|block risky command| Stop["Stop before damage"]

まず覚える失敗地図

失敗事例起きる場面被害先に置く防波堤
.env をコミット「CIで使うから追加して」と頼むAPIキー漏洩、課金、悪用.gitignore と staged file scan
本番DBを削除接続先を確認せずマイグレーションデータ消失、復旧作業DATABASE_URL の環境名チェック
git push --forceコンフリクト解消を急ぐ他人の履歴を破壊ask ルールと保護ブランチ
CIでAIレビュー暴走PRごとに広い権限で実行Actions分とAPI分の請求増max-turns と最小権限
未検証ログを貼る外部入力に命令文が混ざるprompt injectionWeb取得とBashをdeny寄りにする
MCPを広く許可便利そうな外部サーバを追加ローカル情報の読み過ぎ信頼済みMCPだけを許可
承認疲れ連続でOKを押す危険操作の見落としhookで機械的に止める

この表で重要なのは、Claude Code が悪いという話ではありません。公式のSecurity docsにもある通り、Claude Code は読み取り中心の権限や承認フローを備えています。しかし最後に許可するのはユーザーです。だから、疲れている人間の判断に頼らない設定を先に作る必要があります。

実用ユースケース1: 個人開発のAPIキー漏洩を止める

最初の落とし穴は .env です。初心者は「環境変数」は安全な置き場所だと思いがちですが、.env をGitに入れた瞬間にただのテキストファイルになります。Stripe、SendGrid、Anthropic、GitHub token のような値は、漏れた時点で第三者が課金や送信をできます。

まずは値を置かない型だけのファイルをコミットします。

# .gitignore
.env
.env.*
!.env.example
secrets/
*.pem
*.key
*service-account*.json
credentials.json
# .env.example
ANTHROPIC_API_KEY=replace_me
DATABASE_URL=postgres://app_user:password@localhost:5432/app_dev
STRIPE_SECRET_KEY=sk_test_replace_me

次に Claude Code 側の権限を閉めます。deny は拒否、ask は毎回確認、allow は自動許可です。公式のsettings docspermissions docsでは、許可・拒否ルールを settings.json に書けることが説明されています。

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)",
      "Bash(git status)",
      "Bash(git diff *)"
    ],
    "ask": [
      "Bash(git push *)",
      "Bash(npm run deploy *)",
      "Write(./migrations/**)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(rm -rf *)",
      "Bash(curl *)",
      "Bash(wget *)",
      "WebFetch"
    ]
  }
}

この設定は「Claude Code に何もさせない」ためではなく、よく使う安全な確認だけを軽くし、破壊的な操作を重くするためのものです。curlWebFetch を常に使うプロジェクトなら、最初から全許可せず、許可ドメインや用途を決めてから緩めます。

実用ユースケース2: チームのPRレビューで事故を増やさない

チームで怖いのは、Claude Code が提案した変更よりも「レビュー運用が雑になる」ことです。AIレビューがあるから人間レビューを省く、CIが通ったから設定変更を見ない、という流れになると、権限ファイルやワークフローの変更がすり抜けます。

そこで、コミット前にシークレットらしい値と危険ファイルを止める小さな検査を置きます。次のスクリプトは依存パッケージなしで動きます。

// scripts/claude-security-check.mjs
import { execFileSync } from "node:child_process";
import fs from "node:fs";

const args = process.argv.slice(2);
const scanAll = args.includes("--all");
const explicitFiles = args.filter((arg) => arg !== "--all");

function runGit(args) {
  return execFileSync("git", args, { encoding: "utf8", maxBuffer: 10 * 1024 * 1024 });
}

function filesToScan() {
  if (explicitFiles.length > 0) return explicitFiles;
  if (scanAll) return runGit(["ls-files"]).split(/\r?\n/).filter(Boolean);
  return runGit(["diff", "--cached", "--name-only"]).split(/\r?\n/).filter(Boolean);
}

function readTrackedOrWorkingTree(file) {
  if (scanAll || explicitFiles.length > 0) return fs.readFileSync(file, "utf8");
  return runGit(["show", `:${file}`]);
}

const forbiddenPath = [
  /^\.env$/,
  /^\.env\./,
  /(^|\/)secrets\//,
  /(^|\/).*service-account.*\.json$/i,
  /(^|\/)credentials\.json$/i,
  /\.(pem|key)$/i
];

const secretPattern =
  /(sk-ant-[A-Za-z0-9_-]{20,}|sk_live_[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----)/;

let failed = false;

for (const file of filesToScan()) {
  if (forbiddenPath.some((pattern) => pattern.test(file))) {
    console.error(`[blocked] forbidden secret path: ${file}`);
    failed = true;
    continue;
  }

  try {
    const text = readTrackedOrWorkingTree(file);
    if (secretPattern.test(text)) {
      console.error(`[blocked] secret-like value found in: ${file}`);
      failed = true;
    }
  } catch {
    // Ignore deleted or binary files.
  }
}

if (failed) process.exit(1);
console.log("security check passed");
{
  "scripts": {
    "security:staged": "node scripts/claude-security-check.mjs",
    "security:all": "node scripts/claude-security-check.mjs --all"
  }
}

ここでの落とし穴は、検査スクリプトを作っただけで満足することです。npm run security:staged をコミット前の手順、PRテンプレート、CIのどれかに必ず組み込みます。Claude Code に「変更前に security:staged を通して」と頼むだけでは忘れます。忘れない場所に置くのが運用です。

実用ユースケース3: 本番DBとデプロイを守る

本番事故は、コマンドそのものより接続先の取り違えで起きます。DROP TABLE が悪いのではなく、開発DBだと思って本番DBに向けたことが問題です。Claude Code に「古いテーブルを消して」と頼む前に、DATABASE_URL、クラウドプロジェクト、ブランチ名を人間が読める形で確認します。

GitHub Actions で Claude Code を使う場合は、公式のGitHub Actions docsが説明する通り、APIキーはSecretsに置き、権限を必要最小限にします。次の例は「PR差分だけをレビューし、ファイル変更はさせない」前提です。

name: Claude Code guarded review

"on":
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  claude-security-review:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Run repository secret scan
        run: node scripts/claude-security-check.mjs --all

      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: "${{ secrets.ANTHROPIC_API_KEY }}"
          prompt: >
            Review only the pull request diff for secret handling, auth checks,
            destructive commands, and permission changes. Do not modify files.
          claude_args: |
            --max-turns 3
            --disallowedTools "Bash(git push *)" "Bash(npm run deploy *)" "Bash(rm -rf *)"

permissions: contents: read にしているのは、レビューだけならリポジトリ書き込み権限が不要だからです。timeout-minutes--max-turns は請求の暴走を止めるためにも効きます。セキュリティは漏洩だけでなく、予期しない実行時間や課金も含めて考えます。

失敗した後の復旧手順

APIキーが漏れた場合、最初にやることはGit履歴の掃除ではありません。まずキーを無効化します。履歴から消しても、すでに誰かが値をコピーしていたら使われ続けます。順番は次です。

  1. 該当キーをプロバイダ側で停止またはローテーションする
  2. 直近の利用ログと請求を確認する
  3. GitHub Secrets、Vercel、Cloudflare、CIの値を差し替える
  4. Git履歴から値を消し、必要ならGitHubにキャッシュ削除を依頼する
  5. 再発防止として .gitignoresettings.json、検査スクリプトを同じPRで入れる

本番DBを壊した場合は、アプリを止めるか読み取り専用にし、バックアップの時刻、復旧先、失われるデータ範囲を先に決めます。焦ってClaude Codeに「戻して」と頼むと、上書き復旧でさらに壊すことがあります。復旧作業は必ずログを残し、1コマンドずつ人間が確認します。

もう一つ大事なのは、承認ログを後から読める形で残すことです。「誰が、どの依頼で、どのコマンドを許可したか」が分からないと、事故後の再発防止が感想で終わります。小さな個人開発でも、危険操作だけは issue やメモに残しておくと、次に権限ルールを直す材料になります。

復旧後に必ずやるべきなのは、Claude Codeへの頼み方を変えることです。同じ依頼文、同じ権限、同じ検証手順のままでは、次の事故もほぼ同じ形で起きます。たとえば「セキュリティを見て」ではなく、「差分内の認証、シークレット、破壊的コマンド、外部公開設定だけを確認し、修正は提案まで」と書きます。これだけで、AIが勝手に広い修正へ進む確率を下げられます。

実務では、事故の重大度を三段階に分けると判断しやすくなります。レベル1はローカルだけのミスで、たとえば .env.example の書き方が紛らわしい程度です。レベル2は限定された利用者や検証環境に影響するミスで、ステージングのWebhook secret漏洩や、テスト用DBの破壊が入ります。レベル3は本番データ、課金、個人情報、顧客環境に触れるミスです。Claude Codeには、このレベルを先に判定させ、レベル3なら自動修正ではなく調査メモと復旧手順だけを作らせます。

もう一つの落とし穴は、検査を「一度作ったら終わり」にすることです。APIキーの形式、CI権限、クラウド設定、社内の禁止コマンドは変わります。月に一度でよいので、拒否ルール、secret scan、GitHub Actions権限、Claude Codeの許可設定を見直します。特に収益化サイトや問い合わせフォームを持つサイトでは、広告タグ、決済リンク、メール送信、analytics が増えるたびにリスク面も広がります。

公式ドキュメントと関連記事

根拠として読むべき公式ページは、SecurityConfigure permissionsSettingsHooksGitHub Actionsです。特に hooks は、ツール実行の前後に独自チェックを挟む仕組みなので、チーム運用では早めに理解しておく価値があります。

内部の詳しい実装は、/blog/claude-code-security-best-practices/ の全体対策、/blog/claude-code-permissions-guide/ の権限設計、/blog/claude-code-secrets-management/ のシークレット管理と合わせて読むとつながります。

テンプレートを短時間でそろえたい場合は /products/ の設定ガイドとチェックリスト、チームで導入手順を固めたい場合は /training/ の導入相談を使ってください。この記事のコードを自社向けに変えるなら、最初の30分で「禁止ファイル」「本番操作」「AIレビューに持たせる権限」の3点だけ決めるのが効果的です。

実際に試した結果、Masa の検証リポジトリでは .env の誤ステージ、sk_live_ 形式のテスト文字列、広すぎるGitHub Actions権限の3つを公開前に止められました。一方で、正規表現だけでは未知のキー形式を拾えないため、最終的にはクラウド側のローテーション、最小権限、承認前レビューを組み合わせる必要があります。Claude Code を安全に使うコツは、AIを疑うことではなく、人間が疲れても事故にならない足場を先に作ることです。

#claude-code #security #incident #best-practices #devops
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。