每次把代码推上仓库,都可能顺手把数据库密码、云厂商 AK/SK、第三方 API Token 一起提交了上去。密钥泄露是开发者最容易踩、代价也最高的坑之一:一旦明文令牌进了 Git 历史,哪怕立刻删掉,也已经留在了公开镜像和攻击者的爬虫里。gitleaks 是一款开源的密钥扫描工具,能在你提交前和 CI 流水线里自动识别出这些硬编码的敏感字符串。本文从本地扫描讲到 pre-commit 钩子,再到 GitHub Actions 全程接入,帮你把密钥泄露挡在合并之前。
为什么硬编码密钥这么危险
很多团队以为“删掉那次提交就好了”,但现实是:GitHub、Gitee 的公开仓库会被各种爬虫实时镜像,内部私有仓库也常有离职成员、第三方集成、CI 日志把历史暴露出去。攻击者手里有一整套针对令牌格式的自动化扫描脚本,能在几分钟内把你刚 push 的 AK/SK 变成他们云账单上的算力。更麻烦的是,密钥一旦进过历史,彻底清除需要重写整个 Git 历史(git filter-repo),成本远高于一开始就拦住。所以业内的共识是“安全左移”——在提交和合并这两个最低成本的节点直接拦截。
gitleaks 是什么
gitleaks 用 Go 写成,核心逻辑是“正则匹配 + 熵检测(entropy)”:正则负责识别有固定形态的密钥(比如 AWS 的 AKIA[0-9A-Z]{16}),熵检测负责抓“看起来像随机长串”的高熵字符串(比如 32 位以上的 hex)。它内置了 100 多条规则,覆盖 AWS、GCP、GitHub、GitLab、Slack、Stripe 等主流服务商,也支持用一份 .gitleaks.toml 定义你自己的密钥格式。单文件二进制、无外部依赖,本地、容器、CI 里都能直接跑。
本地安装与第一次扫描
安装
# macOS / Linux (Homebrew)
brew install gitleaks
# 或用 Go 直接装
go install github.com/gitleaks/gitleaks/v8@latest
# 或从 release 下载单文件二进制
# https://github.com/gitleaks/gitleaks/releases
gitleaks version
扫描整个仓库(含历史)
detect 是默认子命令,会扫描工作区未提交改动 + 全部 Git 历史,发现命中就返回非零退出码(方便接 CI)。
# 扫描当前仓库,结果导出成 JSON 报告
gitleaks detect --source . --report gitleaks-report.json --verbose
# 只想看,不写报告
gitleaks detect --source . --verbose
只扫未提交改动(pre-commit 用)
提交前钩子不需要扫历史,只需扫已暂存(staged)的内容。早期版本用 gitleaks protect,新版本统一为 gitleaks detect 配合暂存区参数;下面用官方 pre-commit 钩子,它内部帮你处理好只扫本次改动。
读懂扫描报告
扫描发现的每条命中,报告里都会带这些字段,定位问题时直接看就行:
| 字段 | 含义 |
| RuleID | 命中的规则名,如 aws-access-token、github-pat |
| File | 出现密钥的文件路径 |
| StartLine / EndLine | 密钥所在的起止行号 |
| Commit | 所在提交的哈希(扫历史时才有) |
| Entropy | 该字符串的香农熵,越高越像随机密钥 |
命中后先别慌:报告里同时会给出 RuleID 和行号,你就能判断是真密钥还是测试占位符、文档示例。误报就用下一节的基线或 allowlist 处理。
接进 pre-commit 钩子
最省事的本地拦截方式,是配合 pre-commit 框架 在每次 git commit 自动跑扫描。--redact 会把输出里的密钥脱敏,避免泄露到终端日志。
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleaks
args: ["--verbose", "--redact"]
装好框架后执行一次 pre-commit install,之后任何一次提交只要命中规则就会直接被拦下,开发者在本地就能改,不用等到 CI 才被发现。
接进 GitHub Actions CI
pre-commit 只能拦“装了钩子的人”,CI 才是团队级的硬闸门。下面这段 Workflow 在每次 push 和 PR 时跑官方 gitleaks-action;fetch-depth: 0 是为了拉全历史,避免漏掉旧提交里的密钥。
# .github/workflows/secret-scan.yml
name: secret-scan
on: [push, pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITLEAKS_ENABLE_UPLOAD_ARTIFACT: "true"
接入后,PR 里只要出现疑似密钥,流水线直接标红,合并被挡住。结合你已有的 GitHub Actions CI/CD 体系,这一步几乎是零成本的安全增量。
自定义规则:识别你自己的密钥格式
通用规则认不出你们公司的内部令牌。在仓库根放一份 .gitleaks.toml,用 rules 扩展即可。keywords 是性能开关——gitleaks 先用关键词快速过滤文件,命中才跑正则,能大幅提速。
# .gitleaks.toml
title = "gitleaks config extended"
[[rules]]
id = "my-api-token"
description = "Detect MyCompany internal API token"
regex = '''MYTOKEN-[0-9a-zA-Z]{32}'''
secretGroup = 1
keywords = ["MYTOKEN"]
这里的 secretGroup = 1 表示只把正则里第一个捕获组(即 MYTOKEN- 后面的部分)当作密钥上报,避免把前缀也写进报告。
误报与基线管理
老仓库一上来扫可能一堆误报。先生成一份基线,把存量问题“冻结”,之后只拦新引入的密钥:
# 生成基线(把当前命中记录下来)
gitleaks detect --report .gitleaks-baseline.json
# 之后扫描时忽略基线里的存量问题
gitleaks detect --baseline-path .gitleaks-baseline.json --report new.json
# 单条误报也可在文件里用注释放行:
# gitleaks:allow
基线要提交进仓库,团队共用;等存量密钥逐步轮转清理后,再把基线清空、回归“零容忍”。
把密钥扫描做成团队规范
工具只是第一步,关键是写进流程。在 技术方案评审 阶段就把“密钥不进库”列为硬性检查项;把它和 技术债务管理 挂钩,存量密钥泄露风险就是一项要清零的债务;再配合 Git 分支模型 的保护分支规则,PR 不通过扫描就不准合。三道防线(本地钩子 + CI 闸门 + 评审规范)叠加,密钥泄露基本能被堵死。
小结
gitleaks 上手成本极低:本地一条 gitleaks detect 就能扫,pre-commit 钩子拦提交,GitHub Actions 卡合并,自定义规则覆盖内部令牌,基线管理处理存量误报。密钥一旦泄露,补救成本是指数级的,而拦在提交和合并这两个节点,几乎不花什么力气。现在就把这几段配置粘进你的仓库,比哪天半夜收到云厂商的异常账单再去救火,划算得多。
版权声明:
作者:suzhe
链接:https://fsdata.site/2026/09/gitleaks-ci-secret-scanning/
文章版权归作者所有,未经允许请勿转载。