关于 secrets-audit
secrets-audit 是用于查找凭据泄露并审查组织密钥管理方式的安全技能,覆盖代码、历史记录和构建产物检查,以及泄露处置建议。
主要功能
- 01扫描代码、Git 历史和产物中的泄露密钥
- 02审查密钥存储、访问与轮换实践
- 03分级处置、轮换并记录暴露凭据
- 04生成结构化密钥审计报告
适用场景
- 01在公开代码库前后检查泄露
- 02排查 CI 和构建产物中的凭据暴露
- 03评估密钥管理器与工作负载身份实践
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ briiirussell/ cybersecurity-skills --skill secrets-audit安装后在 Claude Code 中输入/secrets-audit确认已加载。
详细介绍
密钥审计 — 凭据泄露与密钥管理审查
分为两部分:(1)查找已泄露到源代码、历史记录或构建产物中的密钥;(2)审计密钥管理态势,判断未来是否会发生泄露。
大多数密钥泄露并非“我们忘了删”,而是“我们从未建立过一套系统,所以每位开发者都各自摸索做法”。此技能涵盖清理和预防。
交叉参考:dependency-audit(构建时暴露导致的 CI 相关密钥风险)、iam-audit(工作负载身份联合,作为长期有效密钥的替代方案)、owasp-audit A02(源代码中的密钥模式)。
第 1 部分 — 查找已泄露的密钥
服务提供商密钥前缀(高置信度模式)
最实用的初步扫描方式,是搜索已知服务提供商密钥前缀。误报很少,匹配结果几乎都是真实密钥。
# Stripe
grep -rE "(sk_live_|sk_test_|rk_live_|whsec_)[A-Za-z0-9]{20,}" . \
--include="*.{js,ts,jsx,tsx,py,rb,go,java,php,sh,env,yml,yaml,json}"
# AWS access keys
grep -rE "(AKIA|ASIA)[A-Z0-9]{16}" .
# AWS secret keys (40 chars, base64-y) — high FP rate, use with caution
grep -rE "[A-Za-z0-9/+=]{40}" . --include="*.env*" --include="*.json"
# GitHub
grep -rE "gh[pousr]_[A-Za-z0-9]{36}" .
# Google Cloud API key + service-account JSON
grep -rE "AIza[A-Za-z0-9_-]{35}" .
grep -rln '"type": "service_account"' . --include="*.json"
# Slack
grep -rE "xox[baprs]-[A-Za-z0-9-]+" .
# OpenAI / Anthropic
grep -rE "sk-[A-Za-z0-9]{32,}" .
grep -rE "sk-ant-[A-Za-z0-9_-]{90,}" .
# Generic high-entropy strings in env files
grep -rE "^[A-Z_]+=[A-Za-z0-9/+=]{32,}$" . --include="*.env*"
要覆盖整个仓库,请使用 git ls-files 限定范围为受跟踪文件,并排除 node_modules:
git ls-files | xargs grep -lE 'sk_live_|ghp_|AKIA[A-Z0-9]{16}|sk-ant-|AIza[A-Za-z0-9_-]{35}' 2>/dev/null
工具
| 工具 | 用途 |
|---|---|
gitleaks detect | 速度快、误报少,可作为提交前检查并在 CI 中运行;支持自定义规则 |
trufflehog git file://. | 通过真实 API 验证发现项(置信度高) |
detect-secrets scan | Yelp 的工具;适用于基线文件工作流 |
| GitHub Secret Scanning | 面向公开仓库免费;自动覆盖大多数服务提供商;启用推送保护后,可在推送时阻止密钥提交 |
| GitLab Secret Detection | 类似功能,内置于 CI |
| GitGuardian / Doppler / Spectral | 商业工具;提供组织级仪表板和历史分析 |
Git 历史记录(人们常忘记的部分)
即使密钥已在最新提交中删除,它仍存在于历史记录中——git log -p、git log -S<secret>,以及任何分叉仓库或本地克隆中都能找到它。
# Search every commit for a pattern
git log -p -S "sk_live_" --all
# Search only deleted lines
git log -p --all | grep -E "^-.*sk_live_"
# Trufflehog historical scan
trufflehog git file://. --since-commit=<first-commit>
# Git history rewrite — destructive, coordinate first
git filter-repo --invert-paths --path config/secrets.yml
# or
bfg --delete-files secrets.yml
**关键注意事项:**重写历史记录需要每位开发者重新克隆仓库,而且所有分叉仓库仍然会暴露该密钥;无论如何,都应将其视为已泄露。务必先轮换密钥,再重写历史记录。
构建产物及其他容易遗忘的位置
密钥泄露并不只发生在 .env 文件中:
- Docker 镜像 —
docker history <image>会显示每一条ENV行;--build-arg SECRET=...会进入镜像层 - CI 环境 — 通过
set -x、console.log(process.env)、错误堆栈跟踪或调试输出记录的密钥 - 前端构建包 —
NEXT_PUBLIC_*/VITE_*/REACT_APP_*环境变量会被打包并发送到浏览器;请搜索打包后的 JS - 崩溃报告 — Sentry / Datadog / Bugsnag 捕获的
process.env快照 - 日志 — 应用程序日志被发送到访问控制比应用程序更宽松的 SIEM
- 备份 — 对包含用户存储的 API 密钥的表执行
pg_dump - 公开的 S3 / blob 存储 —
.env文件被意外上传 - 文档 — README.md 示例中使用了真实密钥,而非占位符
- Slack / Notion / Linear — 为了“测试”粘贴到私信中的密钥,之后从未轮换
- 浏览器 localStorage / cookies — 在共享截图或会话回放中被捕获
对发现的泄露密钥进行分级处理
发现密钥泄露时:
- 确认密钥是否仍有效 — 使用提供商的验证方式(
aws sts get-caller-identity、stripe balance retrieve、curl -H "Authorization: Bearer $TOKEN" ...),不要想当然;一些泄露的密钥可能已被撤销,或仅用于沙盒环境 - 确定暴露时间范围 — 首次出现该密钥的提交时间、仓库公开的时间,以及 CI 日志的保留时间
- 确定影响范围 — 此密钥可以访问什么?可以用它执行哪些操作?检查 IAM 权限、Stripe 是正式环境还是测试环境、GitHub 是
repo还是admin:org - 立即轮换 — 生成新密钥并部署,然后撤销旧密钥(先撤销会导致生产环境中断)
- 审计密钥使用情况 — 检查提供商的审计日志(CloudTrail、GitHub 审计日志、Stripe 事件),查找泄露凭据执行的任何活动
- 然后清理 — 从当前代码中移除密钥,然后可选择重写历史记录(轮换后优先级较低)
- 记录事件 — 编写事件报告,即使轮换过程顺利也要记录;复发模式有助于发现趋势
第 2 部分 — 审计密钥管理状况
密钥存储层级(从最差到最佳)
| 层级 | 模式 | 可接受的情况 |
|---|---|---|
| ❌ | 在源代码中硬编码 | 永不接受 |
| ❌ | 在镜像/构建产物中硬编码 | 永不接受 |
| ❌ | 在共享文档/Slack 中以明文存储 | 永不接受 |
| ⚠️ | 在仓库中的 .env 文件(即使有 .gitignore,也很容易通过推送、备份、存档泄露) | 仅用于引导配置;审计时标记 |
| ⚠️ | 仅使用环境变量 | 临时开发环境中可接受;生产环境中安全性较弱(可在 /proc、崩溃转储和日志中看到) |
| 🟢 | 部署时从密钥管理器获取 | 大多数应用的标准做法 |
| 🟢 | 工作负载身份联合(完全不存储密钥) | 受支持时的最佳做法 |
云提供商的密钥管理器
- AWS Secrets Manager / Parameter Store (SecureString) — 通过 IAM 限定范围的 IRSA / 任务角色 / Lambda 角色集成
- GCP Secret Manager — 通过 Workload Identity 绑定到 GSA,由 GSA 获取密钥
- Azure Key Vault — 通过托管身份获取
- Doppler / Infisical / 1Password Secrets Automation — 跨云,方便开发者使用
审计清单
- Git 历史记录中没有密钥(运行 gitleaks --all)
- 没有提交
.env—.gitignore覆盖.env*(注意保留.env.example) - 运行时获取密钥,而非在构建时嵌入 — 轮换密钥无需重建镜像
- IAM 权限限定到具体密钥 — 服务 A 可以读取密钥 A,不能读取密钥 B
- 轮换周期 — 按密钥类别定义(管理员:30d,服务:90d,与客户共享:按泄露事件响应)
- 轮换已自动化 — 如果需要人工每 90 天运行一次脚本,轮换最终会偏离计划
- 访问有日志记录 — 每次 Get / Decrypt 调用都记录在审计跟踪中
- 工作负载未使用长期有效的云密钥 — 在所有受支持的场景中使用工作负载身份联合(参见
iam-audit) - 紧急访问流程 — 密钥管理器不可用时,如何启动关键服务?(通常做法是:在磁盘上加密缓存,并在重启时严格要求重新获取)
- 跨环境隔离 — 暂存环境绝不能读取生产环境的密钥(使用不同的 KMS 密钥和不同的 IAM)
常见问题
- 从未测试过轮换 — 已配置密钥存储,但从未实际轮换;第一次尝试就会导致生产环境中断
- 将
.env.local部署到暂存环境 — 特定环境的开发密钥越过了环境边界 - 来自 Fork 的 PR 可以访问 CI 密钥 — GitHub 过去的默认行为存在风险;请检查
pull_request_target和密钥的可访问性 - 使用构建参数传递密钥 —
--build-arg AWS_SECRET=...会将密钥留在镜像历史记录中(请改用--secret/BuildKit) - 日志框架在未处理异常时转储
process.env— 需要配置 Sentry / Datadog / Bugsnag 的脱敏功能 - 密钥以普通 Secret 的形式存储在 K8s 中,且 etcd 未启用加密 — base64 是编码,不是加密(参见
container-audit) - 移动应用中包含 OAuth 客户端密钥 — 公共客户端无法安全保管密钥;应使用 PKCE
输出格式
# Secrets Audit Report
## Scope: [repos / environments / managers covered]
## Date: [date]
### Live leaked secrets found
| Provider | Location | First seen (commit / date) | Verified live? | Rotation status |
|---|---|---|---|---|
### Secrets-management posture
| Category | Status | Notes |
|---|---|---|
### Recommendations
| Priority | Item | Owner | Deadline |
|---|---|---|---|
根据 owasp-audit,确定处置规则(固定/延后/接受风险)。
边界
- 仅审计用户有权访问的代码库、CI 系统和基础设施
- 绝不使用发现的密钥访问服务提供商——通过最小化的 API 调用(账户信息,不提取数据)验证密钥是否有效;不得进一步访问
- 对于重写历史记录的操作:未经明确确认且未制定协调通知开发者的计划,绝不继续
- 拒绝帮助收集或利用他人代码库中泄露的密钥
- 如果审计发现属于第三方(供应商、员工个人账户)的凭据,请通知相关方并轮换凭据;不要悄悄修复
参考资料
- OWASP 机密管理速查表
- NIST SP 800-57(密钥管理建议)
- GitGuardian《State of Secrets Sprawl》年度报告——可用于了解行业情况
gitleaks、trufflehog、detect-secrets文档- GitHub Secret Scanning 和 Push Protection 文档
- HashiCorp Vault 架构/最佳实践
- AWS Secrets Manager 最佳实践
- 《Twelve-Factor App》——配置原则
评论
支持 Markdown