Tips & Tricks

Claude Code 引发的7起生产事故:含RCA与预防措施的完整恢复方案

公开7起与 Claude Code 相关的真实生产事故:API密钥泄露、数据库删除、账单爆炸、服务宕机的原因、恢复步骤、根本原因分析及再发防止措施。

“Claude Code 很方便,但在生产环境中使用让我感到害怕”——许多工程师都有这种感觉。这种直觉是正确的

Claude Code 以比普通 IDE 更高的权限操作文件系统和 Shell。同时,不断点击批准按钮会让警惕性逐渐降低——这是人类心理的已知弱点。当这两个因素结合时,生产事故就会发生。

本文将公开 7起与 Claude Code 相关的真实生产事故,包括原因、受影响范围、恢复步骤、RCA(根本原因分析)和再发防止措施。请在贵公司发生事故之前阅读。


案例1:API密钥泄露 → 未授权使用导致约2万元账单

时间线

09:12  指示 Claude Code:"提交 .env 以将环境变量传递给 CI"
09:13  git add .env && git push 在未经审批的情况下执行(allow 列表过于宽松)
09:14  GitHub 通过密钥扫描检测到,发送邮件通知
09:31  AWS 爬虫检测到 OpenAI 密钥,未授权使用开始
11:00  在 OpenAI 控制台确认约2万元账单

恢复步骤

# 步骤1:立即撤销 API 密钥(最高优先级·5分钟内)
# → 在 OpenAI/各服务的控制台中撤销密钥

# 步骤2:从 git 历史中完全删除 .env
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all

# 步骤3:强制推送所有分支
git push origin --force --all
git push origin --force --tags

# 步骤4:添加到 .gitignore 以防止再次发生
echo ".env" >> .gitignore
git add .gitignore && git commit -m "security: add .env to gitignore"

# 步骤5:生成新 API 密钥并配置到 .env 中

RCA

  • 直接原因settings.jsonallow 中包含 Bash(git add*),导致无需确认即可执行
  • 根本原因:将安全配置推迟,优先开发产品代码

预防措施

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash(git add*)",
      "hooks": [{
        "type": "command",
        "command": "git diff --cached --name-only | grep -E '\\.env' && echo '🚨 检测到 .env!中止操作' && exit 1 || exit 0"
      }]
    }]
  }
}

案例2:rm -rf 导致整个项目消失

时间线

14:33  指示:"清理 node_modules 并重新安装"
14:33  Claude Code 执行了 rm -rf node_modules(到此为止正常)
14:34  接着"也删除旧的构建文件"的指示,执行了 rm -rf dist/
14:34  路径解析错误导致执行了 rm -rf dist /src(空格分隔)
14:35  src/ 目录整体消失。git 管理范围外的配置文件也被删除
14:40  git checkout . 恢复了被管理的文件,但 .env、本地配置永久丢失

恢复步骤

# git 管理的文件可以恢复
git checkout .
git clean -fd   # 删除多余文件

# 从 git stash 或 reflog 中查找已删除的文件
git stash list
git reflog

# git 管理范围外的文件(.env 等)从备份恢复
# → 没有备份的情况下,只能从头重新配置

RCA

  • 直接原因:含空格的路径未正确加引号,导致 rm -rf dist /src 被执行
  • 根本原因rm -rfallow 而非 ask

预防措施

{
  "permissions": {
    "deny": ["Bash(rm -rf ~*)", "Bash(rm -rf /*)"],
    "ask": ["Bash(rm*)"]
  },
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash(rm*)",
      "hooks": [{
        "type": "command",
        "command": "echo '⚠️ 检测到删除命令。目标:$CLAUDE_TOOL_INPUT_COMMAND\n5秒后执行。Ctrl+C 中止。' && sleep 5"
      }]
    }]
  }
}

案例3:git push --force 导致3位同事的提交消失

时间线

16:00  指示:"与远程发生冲突,优先本地并覆盖"
16:01  执行了 git push --force origin main
16:01  3位同事当天提交的约200行代码消失
16:10  同事A在 Slack 发帖:"我的提交怎么消失了?"
16:15  原因查明。同事A/B的本地PC上还有,但C已删除本地,永久丢失

恢复步骤

# 通过 reflog 查找消失的提交(在执行者的机器上)
git reflog | head -30
# → 例如:abc1234 HEAD@{3}: --force 之前的提交

# 恢复消失的提交
git checkout -b recovery abc1234
git push origin recovery

# 合并到 main 并整理
git checkout main
git merge recovery --no-ff
git push origin main

RCA

  • 直接原因:解决冲突的意图被解释为 --force 而不是 --force-with-lease
  • 根本原因:main 分支的 force push 没有被列入 deny

预防措施

{
  "permissions": {
    "deny": [
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)",
      "Bash(git push -f *main*)"
    ]
  }
}
<!-- CLAUDE.md -->
## git 规则
- 禁止 `git push --force`
- 解决冲突时使用 `git push --force-with-lease`
- 向 main/master 推送时必须经过用户确认

案例4:DB 迁移失败导致生产数据4万条消失

时间线

10:00  指示:"执行迁移,在 users 表中添加 phone_number 列"
10:01  Claude Code 生成并执行了迁移脚本
10:01  脚本 bug 导致包含 DROP COLUMN 的反向迁移被执行
10:02  生产环境的 users.email 列(NOT NULL)消失
10:02  所有 API 开始返回 500 错误,服务完全停止
10:05  发现障碍,开始调查原因
10:30  从前一天的快照恢复(丢失1天的数据)

恢复步骤

# 1. 立即将服务切换到维护模式
# nginx: return 503;  或者  Vercel: 维护页面

# 2. 确认 DB 当前状态
psql $DATABASE_URL -c "\d users"

# 3. 从备份恢复(RDS 的情况)
aws rds restore-db-instance-to-point-in-time \
  --source-db-instance-identifier mydb \
  --target-db-instance-identifier mydb-restored \
  --restore-time 2026-04-17T23:00:00Z

# 4. 如果列还在,手动添加
ALTER TABLE users ADD COLUMN email VARCHAR(255);
UPDATE users SET email = '(需要恢复)' WHERE email IS NULL;

# 5. 重启服务

RCA

  • 直接原因:生成迁移脚本时混淆了 up/down
  • 根本原因:未在 staging 环境测试,直接在生产环境执行

预防措施

<!-- CLAUDE.md -->
## DB 迁移必要规则
1. 必须在 staging 环境确认后再应用到生产环境
2. 迁移前必须手动备份:
   pg_dump $DATABASE_URL > backup_$(date +%Y%m%d_%H%M%S).sql
3. 包含 DROP COLUMN / TRUNCATE / DELETE(无 WHERE)的脚本,
   必须经过用户确认后才能执行
4. 使用生产环境 DATABASE_URL 时,执行前显示"这是对生产 DB 的写操作,是否继续?"

案例5:无限 API 调用导致一夜产生约5500元账单

时间线

23:00  指示"遇到错误时自动重试",开始批处理
23:01  外部 API 开始返回 503
23:01  重试逻辑无上限运行,每秒持续调用
07:00  次日早晨,Anthropic 发来"使用量接近上限"通知
07:05  确认产生了28,000次 API 调用和约5500元账单

恢复步骤

# 1. 立即停止进程
pkill -f "node batch-process.js"

# 2. 确认计费情况并联系 Anthropic 支持
# → 诚意沟通有时可获得部分退款

# 3. 设置使用量警告
# Anthropic 控制台 → Usage Limits → 设置每月预算警告

预防措施

// utils/retry.ts — 必须使用此工具函数
export async function withRetry<T>(
  fn: () => Promise<T>,
  { maxAttempts = 3, baseDelayMs = 1000, maxDelayMs = 30000 } = {}
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxAttempts) throw err;
      const delay = Math.min(
        baseDelayMs * 2 ** (attempt - 1) + Math.random() * 500,
        maxDelayMs
      );
      console.warn(`Retry ${attempt}/${maxAttempts} in ${Math.round(delay)}ms`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error("unreachable");
}
<!-- CLAUDE.md -->
## API 调用规则
- 重试最多3次,必须使用 exponential backoff
- 绝对禁止 while(true) + API 调用
- 批处理必须明确设置数量上限
- 生产执行前使用 --dry-run 进行冒烟测试

案例6:部署后依赖关系损坏导致服务全线停止

时间线

15:00  指示:"将包更新到最新版本"
15:01  执行 npm update,package-lock.json 大幅变化
15:05  本地构建通过
15:10  执行生产部署
15:12  生产环境依赖包主版本不匹配,启动失败
15:12  503 错误,服务全线停止
15:30  回滚到上一个版本完成

恢复步骤

# Vercel / Cloudflare Pages 的情况:立即重新激活上一个部署
# → 可以从控制台一键回滚

# 用 git revert 还原代码
git revert HEAD~1
git push

# 将 package-lock.json 恢复到之前的版本
git checkout HEAD~1 -- package-lock.json
npm ci  # 严格使用 package-lock.json

RCA

  • 直接原因npm update 升级了主版本,产生了 breaking change
  • 根本原因:跳过了在 staging 环境的部署确认

预防措施

<!-- CLAUDE.md -->
## 包管理规则
- 禁止 npm update(npm update --save-dev 有条件允许)
- 包的主版本升级必须经过用户确认
- 部署前必须在 staging 环境确认运行情况
- 生产部署后监控错误日志5分钟

案例7:权限设置错误导致所有用户数据可被查看

时间线

11:00  指示:"在管理后台的 API 端点添加用户列表"
11:05  /api/admin/users 在未添加认证检查的情况下实现
11:10  生产部署
11:10  发生所有用户个人信息可被任何人访问的状态
13:30  安全审计工具检测到未认证端点
13:35  立即使该端点无效

恢复步骤

# 1. 立即使相关端点无效
# nginx: location /api/admin { return 403; }

# 2. 确认访问日志,确定泄露范围
grep "/api/admin/users" /var/log/nginx/access.log | \
  awk '{print $1}' | sort | uniq -c | sort -rn

# 3. 向受影响用户发出通知(确认个人信息保护法要求)

# 4. 添加认证中间件并部署

RCA

  • 直接原因:“添加到管理后台”的指示没有传达认证要求
  • 根本原因:CLAUDE.md 中没有记载安全要求

预防措施

<!-- CLAUDE.md -->
## API 安全必要要求
- /api/admin/* 端点必须实现管理员认证检查
- /api/user/* 必须实现登录认证检查
- 无需认证即可访问的 API 仅限 /api/public/*
- 添加新 API 时,必须在注释中注明认证级别

故障处理通用流程(Postmortem 模板)

# Postmortem:[故障标题]

## 摘要
- 发生时间:YYYY-MM-DD HH:MM
- 发现时间:YYYY-MM-DD HH:MM
- 恢复时间:YYYY-MM-DD HH:MM
- 影响范围:(用户数/功能/时间段)
- 严重程度:P0/P1/P2/P3

## 时间线
| 时间  | 事件 |
|-------|------|
| HH:MM | 故障发生 |
| HH:MM | 发现 |
| HH:MM | 开始响应 |
| HH:MM | 确认原因 |
| HH:MM | 恢复完成 |

## 根本原因
- 直接原因:
- 根本原因:
- 扩大原因:

## 再发防止措施
| 措施 | 负责人 | 期限 |
|------|--------|------|
|      |        |      |

## 经验教训

总结:防止故障的最低限度配置

// 立即复制并粘贴到 .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(rm -rf ~*)",
      "Bash(rm -rf /*)",
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)",
      "Bash(git push -f *main*)",
      "Bash(DROP TABLE*)",
      "Bash(TRUNCATE *)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)"
    ],
    "ask": [
      "Write(**)", "Edit(**)",
      "Bash(rm*)", "Bash(git commit*)",
      "Bash(git push*)", "Bash(*deploy*)",
      "Bash(npm install*)", "Bash(*migrate*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git add*)",
        "hooks": [{ "type": "command",
          "command": "git diff --cached --name-only | grep '\\.env' && echo '🚨 检测到 .env!中止操作' && exit 1 || exit 0" }]
      },
      {
        "matcher": "Bash(rm*)",
        "hooks": [{ "type": "command",
          "command": "echo '⚠️ 检测到删除命令。5秒后执行。Ctrl+C 中止。' && sleep 5" }]
      }
    ]
  }
}

生产故障是”省下30分钟配置时间”的结果。本文的7个案例,全部可以通过适当的 settings.jsonCLAUDE.md 来预防。

相关文章

参考资料

#claude-code #incident #production #sre #security #postmortem

让你的 Claude Code 工作流更上一层楼

50 个经过实战检验的提示词模板,现在就能复制粘贴到 Claude Code 中使用。

免费

免费 PDF:5 分钟看懂 Claude Code 速查表

只需留下邮箱,我们就会立即把这份 A4 一页速查表 PDF 发送给你。

我们会严格保护你的个人信息,绝不发送垃圾邮件。

Masa

本文作者

Masa

深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。