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.json的allow中包含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 -rf在allow而非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.json 和 CLAUDE.md 来预防。
相关文章
参考资料
免费 PDF:5 分钟看懂 Claude Code 速查表
只需留下邮箱,我们就会立即把这份 A4 一页速查表 PDF 发送给你。
我们会严格保护你的个人信息,绝不发送垃圾邮件。
本文作者
Masa
深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。
相关文章
Claude Code API费用完全攻略:用5个实战技巧将月账单从$450降到$45
用真实数字解析Claude Code API收费机制。通过提示词缓存、模型优化和批量处理,实现从$450到$45/月的90%费用削减——全程公开。
Claude Code的10个危险Prompt模式 | 绝对不能用的指令与安全替代方案
介绍10个绝对不能给Claude Code的危险Prompt模式。了解模糊指令如何导致代码消失、数据库毁坏、账单暴增和密钥泄露,并附上安全替代方案。
Claude Code 安全最佳实践完全指南:API密钥管理、权限设置与生产环境保护
安全使用 Claude Code 的实战指南。从 API 密钥管理到权限配置、基于 Hooks 的自动化检查,再到生产环境保护——附带可直接运行的代码示例。