0

AI代码安全扫描工具免费推荐:6款一句话揪出漏洞与硬编码密钥的神器横向对比与实操指南

2026.08.04 | youres | 76次围观

“上线前扫一遍安全”这件事,绝大多数中小团队都停留在口头。原因不复杂:商业 SAST 动辄按开发者人头收费,开源工具又分散在四五个仓库里,命令、配置格式、报告格式各不相同,光是把它们串起来就要耗掉一个人两周。于是安全扫描要么彻底不做,要么做成了 CI 里一个永远绿灯、没人看的步骤。

AI 编程助手的出现让这件事的门槛降了一大截——你可以用一句话让它写出 Semgrep 自定义规则、生成 Trivy 的 CI 配置、解释一条 CVE 到底影不影响你。但同样地,AI 在安全领域的幻觉代价远高于写业务代码:一条语法合法但永远匹配不到的规则、一个被编造出来的 CVE 编号、一句“这个漏洞已在 x.y.z 修复”的臆断,都会让你误以为自己安全了。

这篇文章横向对比 6 款完全免费(或对个人/开源项目免费)的代码安全扫描工具,给出每一款的真实命令、AI 提示词写法,并重点拆解 AI 在安全扫描场景最容易踩的 5 个坑——这些坑的共同特征是:命令能跑通、报告能生成、CI 显示通过,但实际上什么都没扫到。

一、先分清四层扫描,提问准确率立刻翻倍

大多数人向 AI 提问时说的是“帮我扫一下代码安全”,这句话太模糊,AI 只能猜。代码安全扫描其实是四种完全不同的技术,用的是不同的工具、不同的规则库、发现的是不同类型的问题。先把层级说清楚,AI 的输出质量会有质变。

层级英文缩写扫什么典型问题代表工具
静态代码分析SAST你自己写的源码逻辑SQL 注入、命令注入、路径穿越、硬编码算法弱点Semgrep、CodeQL、Bandit
依赖成分分析SCAlock 文件里的第三方库版本已知 CVE、供应链投毒、许可证违规OSV-Scanner、Trivy
密钥泄露检测Secret Scanning源码 + Git 历史提交AK/SK、Token、私钥、数据库密码gitleaks、Trivy
基础设施配置检查IaC / MisconfigDockerfile、K8s YAML、Terraform特权容器、0.0.0.0 暴露、无资源限制Trivy、Checkov

为什么这个表很重要?举个真实例子:有人问 AI“帮我检查代码里有没有 SQL 注入”,AI 给了一段 Trivy 命令。Trivy 是优秀工具,但它的默认强项是 SCA 和 IaC,对业务代码的注入类逻辑漏洞基本无能为力。命令跑完输出 “No vulnerabilities found”,提问者以为自己没问题,实际上扫描器压根就没往那个方向看。

提问模板:把层级写进第一句。「我要做的是 SAST 静态代码分析,语言是 Python,重点关注命令注入和反序列化,请用 Semgrep 实现」,比「帮我扫代码安全」的可用率高一个数量级。

二、6 款免费工具横向对比

工具主战场免费边界上手难度最适合的场景
SemgrepSAST + 自定义规则CLI 与社区规则库完全免费低(规则语法接近源码本身)团队自定义规范落地、增量扫描
TrivySCA + Secret + IaC + SBOM完全开源免费极低(一条命令四种扫描)容器镜像与仓库的一站式体检
gitleaks密钥泄露(含 Git 历史)完全开源免费极低提交前拦截、历史泄露排查
OSV-Scanner依赖漏洞(Google OSV 库)完全开源免费多语言 lock 文件统一扫描
CodeQL深度数据流分析公开仓库免费,私有仓库需 GHAS高(需学 QL 查询语言)开源项目深挖污点传播链
BanditPython 专项 SAST完全开源免费极低Python 项目快速基线检查

1. Semgrep:唯一值得让 AI 帮你写规则的工具

Semgrep 的规则语法最大的特点是「像写代码一样写规则」——你想匹配什么代码,就把那段代码写下来,把可变部分换成 $X 这样的元变量。这个特性让它成为最适合 AI 生成的安全规则语言。

semgrep scan --config auto .
semgrep scan --config p/owasp-top-ten --severity HIGH .
semgrep scan --config ./rules/ --sarif -o semgrep.sarif .

一条自定义规则的必填字段只有五个:idmessageseveritylanguages,以及 pattern / patterns / pattern-either / pattern-regex 四者中的任意一个。patterns 是逻辑 AND,pattern-either 是逻辑 OR,pattern-regex 走的是 PCRE2 多行模式。

rules:
  - id: dangerous-os-system
    message: 检测到 os.system 直接拼接变量,存在命令注入风险
    severity: HIGH
    languages: [python]
    pattern-either:
      - pattern: os.system(...)
      - pattern: subprocess.call($CMD, shell=True)

2. Trivy:一条命令覆盖四种扫描

Trivy 的杀手锏是 --scanners 参数,可以在一次扫描里同时开启依赖漏洞、密钥、配置错误、许可证四类检查,输出统一在一份报告里。

trivy fs --scanners vuln,secret,misconfig .
trivy image --severity HIGH,CRITICAL --ignore-unfixed nginx:latest
trivy repo https://github.com/user/repo
trivy fs --format cyclonedx -o sbom.json .

--ignore-unfixed 是实战中最该加的一个参数:它会过滤掉“上游还没发布修复版本”的漏洞。这类漏洞你除了等没有任何办法,留在报告里只会淹没真正可修的条目。想给容器镜像本身做减法,可以配合 AI Dockerfile 生成工具的多阶段构建实践,基础镜像瘦一圈,CVE 数量常常能直接掉七成。

3. gitleaks:注意它的命令在近版本里换过一轮

gitleaks 专攻密钥泄露,最大的价值在于它能扫 Git 历史——底层调的是 git log -p,也就是说你把密钥从代码里删掉、提交了一次“移除敏感信息”,它照样能从历史 patch 里揪出来。

gitleaks git -v .
gitleaks dir --redact -f sarif -r gitleaks.sarif ./src
gitleaks git --baseline-path baseline.json .

三种扫描模式分别是 git(扫仓库历史)、dir(扫目录或文件)、stdin(从标准输入读)。配置文件的查找优先级依次是:--config/-c 指定 → 环境变量 GITLEAKS_CONFIG → 环境变量 GITLEAKS_CONFIG_TOML(直接放文件内容)→ 目标路径下的 .gitleaks.toml,四者都没有才用内置默认配置。

另外两个实用细节:--redact 支持传百分比(如 --redact=20 只遮蔽 20%),方便在日志里保留可辨识片段;代码里写 gitleaks:allow 注释可单点豁免,而 --ignore-gitleaks-allow 能强制忽略这些豁免做一次全量复查。

4. OSV-Scanner:Google 的依赖漏洞库,V2 换了命令结构

OSV-Scanner 的工作分两步:先从项目里提取依赖包清单,再拿去和 OSV 漏洞数据库匹配。它的覆盖生态很广,一个二进制搞定 npm / PyPI / Go / Maven / Cargo 等多种 lock 文件。

osv-scanner scan -r ./my-project-dir/
osv-scanner scan -L package-lock.json --format json --output-file result.json
osv-scanner scan image my-docker-img:latest
osv-scanner --licenses="MIT,Apache-2.0" path/to/repository

V2 版本把功能拆成了 scan source(默认,扫源码目录)、scan image(扫容器镜像)、fix(引导式修复)三个子命令。--serve 会把结果渲染成 HTML 并在本地 8000 端口起个服务,比翻终端表格舒服得多。离线环境可以用 --offline-vulnerabilities 配合 --download-offline-databases 预下载数据库。

需要特别提醒:osv-scanner fix 这个引导式修复命令在不受信任的项目上有风险——它可能触发包管理器执行项目里的脚本,或访问项目指定的外部 registry。给别人的仓库做安全审计时,只扫不修。

5. CodeQL:深度最强,但门槛也最高

CodeQL 把代码编译成一个可查询的数据库,然后用 QL 语言写查询去追踪污点从 source 到 sink 的完整传播路径。它能发现跨函数、跨文件的复杂漏洞,这是纯模式匹配类工具做不到的。代价是:需要能成功构建项目、查询语言学习曲线陡峭、扫描耗时以分钟计。公开仓库在 GitHub 上免费启用,私有仓库需要 GitHub Advanced Security。

codeql database create db --language=javascript
codeql database analyze db --format=sarif-latest --output=results.sarif

6. Bandit:Python 项目的三十秒基线

Bandit 只做 Python,规则数量不多,但胜在零配置、跑得飞快,适合当作提交前的第一道粗筛。

bandit -r . -ll -f json -o bandit.json
bandit -r ./app --skip B101,B601

-ll 表示只报告 MEDIUM 及以上级别。B101(assert 语句)在测试代码里满地都是,几乎是必须 skip 的一条。

三、AI 最容易踩的 5 个坑(命令能跑,但等于没扫)

下面这五个坑的共同点:AI 的输出语法完全合法,命令执行不报错,报告也正常生成,CI 甚至是绿的——但扫描的有效性已经归零。这也是它们比语法错误危险得多的原因。

坑 1:gitleaks 的 detect / protect 命令已被废弃

这是当前 AI 出错率最高的一个点。gitleaks 在 v8.19.0 引入了一次命令重构:detectprotect 被废弃,虽然为了兼容仍然可用,但已经从 --help 菜单里隐藏。取而代之的是 gitdirstdin 三种模式。

问题在于,网上绝大多数教程和博客写的都是 gitleaks detect --source . -v,AI 的训练语料里这个写法占压倒性多数,于是几乎每次都会给你旧命令。它现在还能跑,但你写进 CI 里就等于埋了一颗定时炸弹,而且新版本的很多参数行为已经围绕新命令组织。

更值得注意的是,gitleaks 项目本身已经宣布进入 feature complete 状态——后续版本只做安全补丁,不再合入新功能,作者的精力转向了新项目 Betterleaks。这意味着如果你现在做技术选型,需要把「长期演进」这一条单独拿出来评估。这类判断永远不要交给 AI,去看仓库 README 的第一屏。

坑 2:Semgrep 规则的 severity 用了旧值,languages 字段被漏写

Semgrep 的 severity 取值已经更新为 LOW / MEDIUM / HIGH / CRITICAL。老的 ERROR / WARNING / INFO 分别对应 HIGH / MEDIUM / LOW,出于向后兼容仍然能用,但 AI 生成的规则里清一色是老值,这会导致你在按 --severity CRITICAL 过滤时,自己写的规则一条都筛不出来。

比 severity 更隐蔽的是 languages 字段。它是必填项,但如果 AI 填错了值(比如把 JavaScript 写成 javascript 之外的别名,或者给 .sh 文件写了错误的键值),Semgrep 不会报错,只会安静地不匹配任何文件。你看到的输出是 “0 findings”,看起来像是代码很干净,实际上规则根本没有被应用到任何文件上。

自检方法:写完规则后,故意造一个必然命中的样本文件跑一遍。如果连样本都匹配不到,问题一定出在 languages 或 pattern 的缩进上,而不是你的代码真的很安全。

坑 3:AI 编造 CVE 编号和“已修复版本”

这是安全场景下 AI 幻觉危害最大的形态。当你把一份扫描报告贴给 AI,问它“这几个漏洞严重吗、升到哪个版本能修”,AI 有相当高的概率给出一个格式完全正确、看起来非常可信、但实际上并不存在的 CVE 编号,或者一个错误的修复版本号。

原因是 CVE 编号的格式极其规整(CVE-年份-数字),语言模型生成这种结构化字符串毫无压力,但它并没有实时的漏洞数据库。更麻烦的是,它对“这个漏洞在你的代码路径里是否真的可达”这一点,只能靠猜。

正确做法是把 AI 定位成「解释器」而不是「数据源」:漏洞编号、影响版本区间、修复版本,一律以 osv.dev 或 NVD 的原始条目为准;把原始条目粘给 AI,让它帮你翻译成人话、评估在你业务场景下的实际风险、给出升级的兼容性注意事项。这三件事 AI 做得非常好,前面那三件它做不了。

坑 4:OSV-Scanner 的 V1 / V2 命令混用

OSV-Scanner V2 引入了 scan source / scan image 的子命令结构,而 V1 时代的写法是直接 osv-scanner -r ./dir。AI 经常把两代语法拼在一起,产出类似 osv-scanner scan --lockfile=xxx -r 这样的组合。有些组合会直接报错(这反倒是好事),有些则会因为参数被忽略而只扫了一部分目录,输出一份“很干净”的报告。

判断依据很简单:跑 osv-scanner --version,V2 起才有 scan 子命令。写 CI 配置时把版本号锁死,别用 latest,否则某天上游发新版,你的流水线会以“扫描通过”的姿态静默失效。这个原则同样适用于 AI 生成的 CI/CD 流水线配置——所有第三方 Action 和二进制都应当锁版本。

坑 5:只扫工作区不扫历史,以及忘了设置 exit-code

两个动作缺一,安全扫描在 CI 里就是纯装饰。

第一,密钥扫描如果只扫当前工作区(gitleaks dir),那么“提交了密钥 → 发现后删掉 → 再提交一次”的经典场景完全检测不到,而这恰恰是密钥泄露最常见的形态。要扫历史必须用 gitleaks git

第二,很多扫描工具默认即使发现问题也返回 exit code 0,CI 自然一路绿灯。gitleaks--exit-code 默认值是 1(发现泄露即失败),但 Trivy 需要显式加 --exit-code 1,Semgrep 需要 --error。AI 生成 CI 配置时,这几个参数是最常被省略的。

trivy fs --scanners vuln,secret --severity HIGH,CRITICAL --exit-code 1 .
semgrep scan --config auto --error --severity HIGH .
gitleaks git -v --redact .

顺带一提,扫描失败后的告警要真的送到人手上才有意义,可以接到既有的 AI 监控告警配置体系里,别让它烂在流水线日志中。

四、约束式提示词模板

把下面这段作为系统提示词的一部分,AI 输出安全扫描配置的可用率会有明显提升。核心思路只有一条:宁可让它说“不确定”,也不要让它编。

你是资深应用安全工程师。请为我生成 [工具名] 的扫描配置,遵守以下硬性要求:

1. 只使用你确定存在的命令、子命令和参数;不确定的宁可不写,并单独列出「需要我确认的点」。
2. 明确声明你假设的工具主版本号(如 Trivy v0.5x / gitleaks v8.2x / OSV-Scanner v2)。
3. 不要输出任何具体的 CVE 编号、漏洞评分或「已在某版本修复」的结论。
4. CI 场景必须显式设置失败退出码,并说明该参数在此工具中的默认行为。
5. 密钥扫描必须区分「工作区扫描」与「Git 历史扫描」,并说明各自命令。
6. 自定义规则必须附带一个必然命中的最小样本,用于验证规则真的生效。
7. 报告格式统一输出 SARIF,便于多工具结果汇总。
8. 最后列出本次配置用到的全部命令与参数清单,供我逐条核对。

第 1 条和第 8 条是压制幻觉的关键组合:前者给了模型“承认不知道”的许可,后者强制它把所有主张摊开、便于你一眼扫过去发现异常。第 6 条则是针对 Semgrep 那类“静默不匹配”问题的专门防御。

五、四道校验流水线

AI 给出配置之后,别直接扔进 CI。按下面四步过一遍,成本大约十五分钟,能挡掉九成问题。

第一道:命令存在性验证

把 AI 给的每一条命令的 --help 跑一遍,确认子命令和参数真实存在。这一步专治坑 1 和坑 4。

gitleaks --help
osv-scanner scan --help
trivy fs --help
semgrep scan --help

第二道:阳性样本验证

这是最容易被跳过、却最有价值的一步。故意在临时目录里放一个必然触发的样本——一段明显的硬编码密钥、一行 os.system(user_input)、一个已知有漏洞的旧版本依赖——然后跑扫描。如果扫不出来,说明你的配置有问题,而不是代码很安全。

# 造一个必然命中的密钥样本
mkdir /tmp/sectest && cd /tmp/sectest && git init
echo 'AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' > config.env
git add . && git commit -m test
gitleaks git -v .   # 必须报出 1 条 finding

第三道:SARIF 统一汇总 + 误报治理

六款工具六种报告格式,人工看会疯掉。全部输出 SARIF,用一个脚本合并,或直接上传到 GitHub Code Scanning 界面统一查看。

误报治理的原则是「有记录的忽略」而不是「关掉规则」:gitleaks 用 --baseline-path 建立基线,Trivy 用 .trivyignore,Semgrep 用 .semgrepignorenosemgrep 注释。每一条忽略都应当带上原因和有效期,否则半年后没人知道为什么这条被关了。

第四道:人工五项清单

  1. 扫描范围是否覆盖了 Git 历史,而不只是当前工作区?
  2. CI 是否会因为发现高危问题而真的失败(退出码非 0)?
  3. 所有工具版本是否锁定,而非使用 latest?
  4. 报告是否有人真的会看,还是只存在于流水线日志里?
  5. 忽略清单里的每一条,是否都能说清为什么忽略?

六、三个真实踩坑案例

案例一:绿灯跑了三个月的密钥扫描

某团队在 CI 里加了 gitleaks,一直是绿的,大家很满意。直到一次外部安全评估,从仓库历史里翻出了七个月前提交的一组云厂商 AK/SK。复盘发现,CI 里用的是 gitleaks dir .——只扫工作区。那组密钥在提交后第二天就被从代码里删掉了,但历史 patch 里完好无损地躺着。

教训:dir 适合扫非 Git 目录或构建产物;只要目标是 Git 仓库,就该用 git 模式。两者可以都跑,但 git 不能少。

案例二:AI 编造的 CVE 让团队白升了一次级

某项目扫出十几个依赖漏洞,负责人把报告贴给 AI 让它排优先级。AI 输出了一份非常专业的分级表,其中标红的一条附带了具体 CVE 编号和“升级到 4.2.1 即可修复”的结论。团队照做,升级引发了两个接口的行为变更,回归测试花了一整天。事后核对 osv.dev,那个 CVE 编号根本不存在,真实的修复版本也不是 4.2.1。

教训:让 AI 排优先级可以,但它给出的任何编号和版本号都必须回到原始漏洞库核对。判断线上影响面时,配合 AI 日志分析工具看真实调用路径,比听 AI 猜靠谱得多。

案例三:Semgrep 自定义规则半年没匹配到任何东西

某团队让 AI 写了一批内部编码规范的 Semgrep 规则,跑起来一直 0 findings,大家以为规范执行得很好。半年后有人手动检查,发现违规代码遍地都是。排查下来,问题出在规则文件里 languages 写成了 [js]——这不是 Semgrep 接受的键值,规则被静默跳过,既不报错也不匹配。

教训:任何新增规则上线前,必须用阳性样本验证一次。「0 findings」在安全领域从来不是好消息,它首先应该被当作「配置可能有问题」的信号。

七、组合技:不要让 AI 从零发明规则

这是全文最实用的一条建议:不要让 AI 凭空创作安全规则,让它做「改写」而不是「创作」。

Semgrep 官方 Registry 有数千条经过生产验证的规则,覆盖 OWASP Top 10、各主流框架的常见误用。正确的工作流是:

  1. 先用 semgrep scan --config p/owasp-top-ten . 跑一遍官方规则集,看看能命中什么。
  2. 找到最接近你需求的那条官方规则,把它的 YAML 完整贴给 AI。
  3. 让 AI 在这条规则的基础上做修改——换函数名、加一个 pattern-not 排除白名单、调整 severity。
  4. 用阳性样本验证改写后的规则确实生效。

这样做的幻觉率比让 AI 从零写规则低一个数量级,因为模板的骨架是真实的,AI 只需要做局部替换。同样的思路适用于其他配置类工作——Kubernetes YAMLNginx 反向代理配置都遵循这个规律:给 AI 一个已验证的模板做改写,永远比让它凭空生成更可靠。

八、五类高频误报及处理方式

扫描器接进来的第一周,报告里通常有七成是噪音。如果不做治理,团队很快就会形成「反正都是误报」的心理,扫描就此名存实亡。下面五类是出现频率最高的,处理方式也最固定。

误报类型典型表现推荐处理
测试代码里的假密钥单元测试的 mock token、示例 AK加入 baseline 或 gitleaks:allow 注释,不要整目录排除
上游未修复的依赖漏洞报出 CVE 但没有可升级版本Trivy 加 --ignore-unfixed,单独建一份跟踪清单
不可达的依赖漏洞漏洞在你从未调用的函数里记录忽略原因与复查日期,不要永久关闭
Bandit 的 assert 告警B101 在测试文件里刷屏--skip B101,但仅对测试目录生效
构建产物被重复扫描node_modules、dist 里的第三方代码用 ignore 文件排除产物目录,而非降低 severity

治理误报有一条铁律:永远忽略「具体的某一条 finding」,而不是「整条规则」或「整个目录」。前者的影响面是可控的,后者会在你毫无察觉的情况下把未来的真问题一起吞掉。gitleaks 的 --baseline-path 就是为此设计的——它记录的是当前已知的具体条目,新出现的泄露依然会报。

另一条同样重要:给每条忽略写上「为什么」和「什么时候复查」。半年后接手的人看到一条没有注释的 ignore,只有两个选择——盲目相信,或者花半天重新分析。两个选择都很糟糕。

九、什么时候该上,什么时候不必

不是所有项目都需要六款工具全上。按项目形态做个简单的决策:

  • 个人项目 / 内部工具:只上 gitleaks 一款,接成 pre-commit hook。密钥泄露是唯一会造成实质损失的风险,其他的可以缓。
  • 对外提供 API 的服务:gitleaks + OSV-Scanner + Semgrep 三件套接进 PR 检查。注入类漏洞和依赖 CVE 是主要攻击面。
  • 容器化部署的生产服务:在上面基础上加 Trivy 的镜像与 IaC 扫描,覆盖基础镜像漏洞和配置错误。
  • 开源项目:直接启用 GitHub 的 CodeQL(公开仓库免费),深度最高且零维护成本。
  • 还没有 CI 的项目:先别想扫描,把流水线搭起来是更优先的事。

过早引入过多工具的典型后果是:报告没人看、误报没人治、CI 时间从两分钟涨到十五分钟,最后被整体注释掉。安全工具的价值不在于装了几个,而在于是否真的有人在响应它的输出。

十、一套可以直接抄的最小配置

如果你只想花二十分钟把安全扫描接进项目,用下面这套:三个工具,覆盖 SAST、SCA、Secret 三层,全部免费。

# 1. 依赖漏洞(每次 PR)
osv-scanner scan -r . --format sarif --output-file osv.sarif

# 2. 密钥泄露(含历史,每次 PR)
gitleaks git -v --redact -f sarif -r gitleaks.sarif .

# 3. 静态代码分析(每次 PR,只报高危)
semgrep scan --config auto --severity HIGH --error --sarif -o semgrep.sarif .

# 4. 每周一次全量深扫(含 IaC 和许可证)
trivy fs --scanners vuln,secret,misconfig,license --severity HIGH,CRITICAL .

PR 阶段只跑前三条,控制在两三分钟内,不影响开发节奏;全量深扫放到定时任务里,结果单独送到安全负责人手上。命令行不熟悉的话,可以配合 AI 命令行助手把这些命令解释清楚再落地。

结语

AI 让安全扫描从「需要专职安全工程师」变成了「一个后端也能搭起来」,但它同时也制造了一种新的风险:看起来在扫,实际上没扫。语法错误会立刻暴露,而配置失效是沉默的——它会一直给你绿灯,直到出事那天。

所以这篇文章反复强调的其实只有一件事:用阳性样本验证你的扫描器真的在工作。造一个必然命中的样本,跑一遍,看它报不报。这个动作只要三十秒,却是区分「真安全」和「假安全」的唯一可靠方法。工具会更新、命令会废弃、AI 会幻觉,但阳性样本永远不会骗你。

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论