怎么防 AI 编程助手把密钥推进公开仓库?gitleaks 三道防线实战
AI 编程助手把「连续授权」变成了日常工作流:授权一次,之后读写文件、跑命令、推提交一路绿灯。安全公司 Apiiro 最近分析了 Claude Code 的「不再询问」(Don’t Ask Again)授权模式,结论相当扎眼——开发者一次性放行后,助手批量操作把密码和 API key 一起打包进了公开 GitHub 仓库,已确认 1,122 个文件泄露密钥。
这不是某个工具的专属缺陷,而是「高授权 + 高速度」agent 工作流的通病:工具越顺手,失误越成批。人工手敲命令一天 push 几次,agent 一小时就能推几十次——以前靠「小心点」能混过去的环节,现在必须装机器闸门。这篇给出三道可落地的防线和一条应急流程,全部用开源工具实现,照着做半小时能装完。
第一步:先查存量——gitleaks 扫全部提交历史
gitleaks 是目前最常用的开源密钥扫描器,Go 编写、单二进制、无依赖。安装:
brew install gitleaks
扫整个仓库的全部提交历史(不是只扫当前工作区):
cd your-repo
gitleaks detect --source . --report-path leaks.json --report-format json
终端会输出这样的摘要:
12:47PM INF 432 commits scanned.
12:47PM INF scan completed in 41.2s
12:47PM WRN leaks found: 3
报告 JSON 里每个 finding 都带 file、commit、rule、secret、startLine 字段。重点盯三条内置规则:AWS Access Key、Generic API Key、Private Key。两个注意点:detect 默认扫历史,最新一轮提交也在覆盖范围内;基于熵值的规则会误报,先人工确认 finding 里的 secret 字段是不是真密钥,再决定走轮换流程。
第二步:装闸门——pre-commit 拦住未来的提交
存量查完,接着挡增量。用 pre-commit 框架把扫描挂进提交流程:
pip install pre-commit
仓库根目录加 .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: gitleaks
name: gitleaks
entry: gitleaks protect --staged --redact --verbose
language: system
pass_filenames: false
激活并验证(拿一条 AWS 测试格式密钥试闸):
pre-commit install
echo "aws_key = AKIAIOSFODNN7EXAMPLE" > test.txt
git add test.txt && git commit -m "test"
# 预期:commit 被拦截,输出 leaks found,退出码非零
三个参数各有用途:–staged 只扫暂存区所以是毫秒级,不影响提交体验;–redact 保证钩子的报错输出里不回显密钥本身(报错信息也会进日志);language: system 用本机安装的 gitleaks,不拉远程仓库。
个人闸门之外,团队层面再加一道 CI 兜底:流水线里跑一次全量 gitleaks detect。原因很直接——pre-commit 钩子可以被 --no-verify 绕过,CI 里的扫描拦的是绕过的人。
第三步:管住 agent 本身——把密钥挡在它的权限外
前两道防线管仓库,第三道管工具。Claude Code 的权限在 ~/.claude/settings.json 里配置,给敏感文件显式加 deny 规则:
{
"permissions": {
"deny": [
"Read(.env*)",
"Read(**/*.pem)",
"Read(**/id_rsa*)",
"Read(**/credentials*)",
"Edit(.env*)"
]
}
}
比配置更重要的是三条操作习惯:
一,不用全局 Don’t Ask Again。 放行范围按项目给:新项目回到逐次确认模式,跑熟了再对这个项目放宽。1,122 个泄露文件的共同点就是「授权动作一次、风险敞口无限」。
二,别在含凭证的目录起 agent 会话。 工作目录里有什么,工具就能读什么。密钥集中放一个专用目录(比如 ~/.secrets),然后对整个路径加 deny——比逐个文件写规则可靠。
三,别拿 .gitignore 当防线。 ignore 只能防「顺手推上去」,挡不住 agent 显式的 read + write + commit 组合操作。真正的闸门必须放在 pre-commit 这一层——文件不被提交,泄露链条就断了。
已经泄露了:轮换永远排在清洗前面
存量扫描报出真泄露,处置顺序不能反:
先作废轮换密钥(AWS 换新 key、GitHub token revoke 后重发、数据库改密码)——这是唯一真正止损的动作。密钥一旦进了公开仓库,自动扫描机器人几分钟内就会把它捡走,存活窗口以分钟计。
再清洗 git 历史:
pip install git-filter-repo
echo "AKIAIOSFODNN7EXAMPLE==>REMOVED" > replacements.txt
git filter-repo --replace-text replacements.txt
git push --force --all
git push --force --tags
顺序反了就是白干:历史洗得再干净,密钥本身还活着,等于给爬虫留了一扇门。force push 之后通知协作者重新 clone 或 fetch 后 rebase 到新历史,避免旧提交被原样推回来。
防线优先级总结
轮换止损 > 提交前拦截 > 历史扫描。扫描工具的价值在发现存量和拦截增量,替代不了密钥轮换;agent 把犯错的单位从「一条命令」放大到「一批操作」,闸门就要相应前移。三道防线装完,AI 助手该用接着用——效率不减,兜底常在。
参考来源:
- Apiiro:Claude Code「不再询问」授权模式密钥泄露研究报告
- Gitleaks 文档:密钥检测规则与 pre-commit 集成
- git-filter-repo 使用手册
王亚博(Abel Wang)
更多推荐



所有评论(0)