开源项目有个尴尬处境:代码是公开的,安全债也是公开的。人工逐行看几千行 diff 不现实,商业 SAST 工具又要走预算审批。Anthropic 放出了两条可自用的路径——Claude Code 内置的安全审查命令,以及开源的 security-review GitHub Action。把它们组合起来,能给仓库做一次覆盖"改动 + 依赖 + 模型文件"的体检,产出一份能直接排期的修复清单。
先说清"免费"的边界:这两个工具本身开源、可自由获取和自托管;模型调用是否产生费用取决于你的账号方案,以 Anthropic 官方计费页面为准。下面照抄即可跑通。
这篇能做出什么
走完整个流程,你会得到 4 份报告和 1 张优先级表:
1. reports/diff-review.md:当前分支相对主干的安全问题,每条带 文件:行号、证据片段、触发条件和严重级别
2. reports/repo-scan.md:全仓库模式扫描结果(危险反序列化、命令注入、硬编码密钥等)
3. reports/deps.md:依赖漏洞清单,按"能否被外部触发"重新排序
4. reports/models.md:模型权重文件的来源与加载方式核查表
5. 一张 P0–P3 修复优先级表,可直接贴进 issue 或 PR 描述
报告里每条长这样,是能直接动手的粒度:
```markdown
[P0] 不可信 pickle 反序列化
- 位置: serving/loader.py:42
- 证据: torch.load(path) # 未限制加载行为
- 触发: 任何能替换 models/ 下 .pt 文件的角色
- 影响: 加载即执行任意代码
- 修复: torch.load(path, map_location="cpu", weights_only=True)
或迁移到 safetensors 格式
```
前置条件清单
动手前确认这几项:
- Node.js 与 npm:Claude Code 通过 npm 分发,版本要求以官方文档当前版本为准
- Anthropic 账号或 API Key:本地交互使用走登录流程即可;CI 场景需要一个 Key
- 仓库的可写副本:扫描过程只读源码,但报告要写到本地目录
- Git 历史完整:改动级审查需要能对比主干,浅克隆会失败
- Python 项目:建议准备虚拟环境,装
pip-audit - 可选:
osv-scanner、npm audit、modelscan或picklescan,作为 AI 扫描的交叉验证
分步骤
第一步:装好 Claude Code 并确认能跑
```bash
npm install -g @anthropic-ai/claude-code
claude --version
```
然后进入目标仓库并启动:
```bash
cd /path/to/your-repo
claude
```
首次运行会走登录授权。团队或 CI 场景改用环境变量:
```bash
export ANTHROPIC_API_KEY="sk-ant-..."
```
这个 Key 只放在本地 shell 或 CI secret 里,不要写进仓库任何文件。
第二步:改动级安全审查(看 diff)
先切到你要审的分支,工作区保持干净:
```bash
git fetch origin
git checkout -b security-check origin/your-branch
```
在 Claude Code 交互界面里,直接输入内置命令:
```text
/security-review
```
它会分析当前分支相对主干的改动,逐条列出安全问题、位置和修复建议。如果你的版本没有这个命令,用第三步的提示词模板替代即可,效果接近。
需要脚本化、把结果落盘时,用非交互模式:
```bash
mkdir -p reports
claude -p "审查当前分支相对 origin/main 的全部改动。按安全问题逐条输出:文件:行号、证据代码片段、触发条件、影响、修复方案、严重级别(P0-P3)。没有发现问题的类别也要明确说明。" \
> reports/diff-review.md
```
第三步:全仓库扫描(不只看 diff)
只审 diff 会漏掉历史遗留问题。准备一份固定的提示词文件,让每次扫描口径一致:
```markdown
<!-- security-scan-prompt.md -->
你是安全审计员,正在审查一个开源仓库。请按以下检查项逐一排查:
1. 反序列化:pickle.load / torch.load / joblib.load / yaml.load(未用 SafeLoader)等
2. 命令执行:os.system、subprocess 带 shell=True、eval、exec
3. 注入类:SQL 字符串拼接、模板注入、路径穿越(../ 拼进文件路径)
4. 网络类:SSRF(用户可控 URL 直接请求)、未校验的重定向
5. 密钥与凭据:硬编码的 token、密码、私钥、内网地址
6. 权限与配置:过宽的文件权限、关闭 TLS 校验、调试模式默认开启
7. 日志与错误:异常堆栈直接返回给客户端、日志里打印敏感字段
输出要求:
- 每条包含 文件:行号、证据片段、触发条件、影响、修复方案
- 严重级别用 P0/P1/P2/P3
- 不确定的标注"待人工确认",不要猜测
- 按严重级别从高到低排列
```
运行:
```bash
claude -p "$(cat security-scan-prompt.md)" > reports/repo-scan.md
```
仓库很大时可以按目录分批跑,一次喂一个子目录,结果合并。这样既避免上下文超限,也方便定位。
第四步:依赖体检
先让成熟工具把原始数据拉出来:
```bash
Python 依赖
pip install pip-audit
pip-audit -r requirements.txt -f json -o reports/pip-audit.json
Node 依赖
npm audit --json > reports/npm-audit.json
通用(按官方文档安装)
osv-scanner --lockfile=package-lock.json
```
然后把原始结果交给 Claude 做"可利用性"排序——原始报告经常几十上百条,直接看没法排期:
```bash
claude -p "读取 reports/pip-audit.json 与 requirements.txt。
按以下三条标准重新排序,不要照抄原来的顺序:
1) 这个包是否在生产路径上被真正调用
2) 漏洞是否可被外部输入触发
3) 是否存在已发布的修复版本
输出 P0-P3 清单,每条给出升级命令或临时缓解措施(如锁定输入、加校验、关闭该功能)。" \
> reports/deps.md
```
关键点:依赖漏洞不等于你的项目可被利用。一个只在开发脚本里用到的工具包报高危,和核心请求路径上的解析库报高危,处理顺序完全不同。
第五步:模型与权重文件体检
这一步是 AI 项目特有的,也是最容易出事的地方。先盘清家底:
```bash
find . -type f \( -name "*.pkl" -o -name "*.pt" -o -name "*.bin" \
-o -name "*.h5" -o -name "*.ckpt" -o -name "*.joblib" \) \
-not -path "./.git/*" -print
sha256sum models/* 2>/dev/null
```
再扫加载代码:
```bash
grep -rnE "torch\.load|pickle\.load|joblib\.load|yaml\.load\(|eval\(|exec\(|os\.system\(|shell=True" \
--include=*.py . | grep -v "\.git/"
```
把文件清单和命中结果一起交给 Claude 判断:
```bash
claude -p "以下是仓库中的模型文件清单和一处反序列化调用点。
请判断:(1) 每个格式的反序列化风险等级;(2) 哪些调用点缺少安全参数;
(3) 哪些可以迁移到 safetensors 或 ONNX;(4) 给出需要校验哈希的文件列表。" \
> reports/models.md
```
判断依据可以记住这几条通用原则:safetensors 和 ONNX 属于纯数据格式,加载时不执行代码;.pkl、.pt、.joblib、.ckpt 这类基于 pickle 的格式在加载阶段就可能执行任意代码,只应从可信发布方获取并校验哈希。第三方模型扫描器(如 modelscan、picklescan)可以作为交叉验证,能力范围以各自官方文档为准。
第六步:合成修复优先级
把四份报告丢给 Claude 合并,用统一的判定标准:
```bash
claude -p "综合 reports/ 目录下的四份报告,输出一张修复优先级表。
判定标准:
P0 = 可被未认证的外部人员触发,且导致代码执行或数据泄露
P1 = 需要认证或特定配置才能触发,影响核心功能
P2 = 需要本地权限,或影响面局限在开发环境
P3 = 加固类建议,无直接可利用路径
每条给:级别、问题、位置、修复动作、预估工作量。" \
> reports/priority.md
```
P0 和 P1 当天建 issue 并指派;P2 排进迭代;P3 攒成一次加固 PR 批量处理。
第七步:接进 CI(可选)
想让每个 PR 自动过一遍,可以用开源的 security-review GitHub Action。下面的结构供参考,with: 下的参数名以该仓库 README 为准:
```yaml
.github/workflows/security-review.yml
name: security-review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: anthropics/claude-code-security-review@main
with:
claude-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
```
新增仓库 secret 时,路径是 Settings → Secrets and variables → Actions。注意来自 fork 的 PR 拿不到 secret,需要在 workflow 里加条件跳过或改用其他触发方式。
最后把报告目录排除出版本控制:
```gitignore
reports/
```
常见坑与排错
只审 diff,漏掉历史问题。 内置审查命令盯的是改动。每季度单独跑一次全仓库扫描,把 repo-scan.md 和上一版做 diff,看新增了哪些风险点。
扫描产物里带密钥。 AI 会把命中的硬编码凭据原样写进报告。先用 git-secrets 或 GitHub 的 secret scanning 清理,再跑扫描;报告目录直接 gitignore。
结果全是泛泛而谈。 提示词里没说清输出格式时,容易得到"建议加强输入校验"这类废话。强制要求 文件:行号 加证据片段,颗粒度立刻下来。
一次喂整个仓库。 上下文超限后会开始丢文件。按目录分批,或者先写个脚本把每个文件截断到合理长度再喂。
假阳性太多导致没人看。 让人工复核后,在仓库里维护一份 security-ignore.md,写清"哪条、为什么不修、什么条件下重新评估"。有记录的忽略才是有效忽略。
依赖报告全标高危。 npm audit 和 pip-audit 的评级基于 CVSS,不等于你的实际暴露面。必须经过第四步的可利用性重排。
模型文件直接塞给模型分析。 权重动辄几个 GB,传不进去也没必要。只喂文件清单、哈希和加载代码。
CI 里权限给太宽。 Action 只需要读代码、写 PR 评论。contents: read 加 pull-requests: write 就够,不要开 write-all。
非交互模式跑不动。 claude -p 遇到需要执行的命令时可能被权限拦住。CI 场景按官方文档配置好允许的工具范围,参数名以官方文档为准。
下一步建议
跑通一次之后,把体检变成习惯:
1. PR 模板加自查项:在 .github/pull_request_template.md 里放一句"改动是否涉及反序列化、命令执行、文件路径拼接?"
2. 依赖扫描上定时任务:用 schedule 触发,每周跑一次依赖检查,新披露的漏洞能第一时间发现
3. 补一个 SECURITY.md:写清漏洞上报渠道和响应时限,开源项目收到安全报告时不会手忙脚乱
4. 加 pre-commit 钩子:用 detect-secrets 之类的工具在提交前拦住密钥
5. 生成 SBOM:把依赖清单固化成软件物料清单,出供应链事件时能快速回答"我用了没有"
6. 轮转历史凭据:扫描一旦发现硬编码密钥,改代码只是第一步,那把 Key 要立刻作废重发
体检的价值在"改完",不在"扫完"。先把 P0 清干净,再谈工具升级。
