一份安全报告只有变成被合并的修复才有用。CodeAuditAgent 的报告正是围绕这一点设计的:每个问题都具体到足以快速核实,并附带一个你可以改造使用的补丁。本文解释报告的每一个部分、在没有专职安全工程师时如何分诊,以及如何确认你的修复确实生效。
会审计什么
一次审计运行在一个公开 GitHub 仓库或你粘贴进来的一段代码片段上。对仓库而言,CodeAuditAgent 读取默认分支。私有仓库无法通过 URL 审计,目前也还没有拉取请求评论;结果存放在控制台和导出文件中。
读取仓库的多少内容取决于你的方案。免费版覆盖 1 个仓库、每月 3 次审计,每次审计最多 20 个文件。Starter 每月 $49,覆盖 5 个仓库、50 次审计,每次审计 40 个文件。Pro 每月 $199,覆盖不限数量的仓库、500 次审计,每次审计 80 个文件。单个大于 60 KB 的文件会被跳过。每月审计次数在每个日历月开始时(UTC)重置。在审计整个仓库之前,粘贴代码片段也是一种快速检查某个你担心的文件的方式。
当有文件因为这些限制被排除在外时,报告会被标注为部分快照。请认真对待这个标注。一份干净的部分快照报告,意味着被读取的那些文件看起来是干净的,而不是整个仓库是干净的。如果你最关心的代码被略过了,请把它作为代码片段审计,或者换一个覆盖更多文件的方案。
风险评分
每份报告顶部都有一个 0 到 100 的风险评分;Markdown 导出还会在它旁边标注总体严重程度。数值越高风险越大。它是该次审计中所有问题的汇总,主要有两个用途:判断查看某个仓库的紧迫程度,以及跟踪它是否在随时间变好。
不要过度解读不相关仓库之间的细微差别。评分总是相对于被审计的内容而言的,而部分快照看到的代码更少。把同一个仓库在修复前后做对比,才是这个数字最有意义的地方。
严重程度与置信度
每个问题都有一个严重程度和一个置信度。它们回答不同的问题:严重程度是说如果这个问题属实会有多糟,置信度是说审查者有多确信它属实。
- 严重:可直接利用且影响严重,比如公开端点上的注入、身份认证绕过或暴露的生产凭据。
- 高:一个需要某些前提条件的真实漏洞,或者影响显著但有限的漏洞。
- 中:与其他漏洞组合起来才重要的弱点,或者影响中等的弱点。
- 低:加固类问题和纵深防御上的缺口。
- 信息:值得知道、但本身不构成漏洞的观察。
置信度分为高、中、低。高置信度的问题在被读取的代码中有明确证据。低置信度的问题通常取决于审计看不到的东西,比如另一个文件里的中间件、一条数据库策略,或者部署时才设置的配置值。低置信度不代表可以忽略;它意味着应当由人去核实缺失的上下文再动手修。
一个问题的结构
每个问题都遵循同样的结构,你可以按固定的顺序核实它。
- 标题与 CWE:弱点的类别,比如表示通过用户可控键绕过授权的 CWE-639。CWE 会告诉你该期待哪一类修复。
- 位置:文件和行号,便于你直接打开代码。
- 证据:从文件中原样引用的相关代码。请核对这段引用是否与你当前的代码一致;如果那一行已经变了,这个问题可能已经过时。
- 攻击场景:攻击者会如何一步步地利用这个弱点。这是判断它在你的上下文中是否成立的最快方式。
- 修复补丁:一段风格贴合周边代码的建议改动。
请把补丁当作一个有力的起点,而不是可直接合并的提交。它是基于审计读取到的代码写的,因此可能不了解你的辅助函数、你的 ORM 约定,或代码库中别处的某个调用方。典型的补丁短小而有针对性:
--- a/app/api/invoices/[id]/route.ts
+++ b/app/api/invoices/[id]/route.ts
@@
- const invoice = await db.invoice.findUnique({ where: { id } });
+ const invoice = await db.invoice.findFirst({
+ where: { id, userId: session.user.id },
+ });
if (!invoice) return Response.json({ error: 'not_found' }, { status: 404 });做得好的地方与后续步骤
报告也会列出做得好的地方:参数化查询被一致地使用、密钥从环境变量加载、严格的 Cookie 配置。这些值得一读。它们告诉你哪些模式应当保留并复制到新代码里,在向别人说明一个代码库的现状时也很有用。
建议的后续步骤部分会把这些问题变成一份有序的计划。它常常会把相关问题归为一组,例如几处缺失的所有权校验,用一个共享的辅助函数一次修好,好过打五个各自独立的补丁。
小团队的分诊流程
没有安全工程师时,风险不在于忽视报告;而在于花一整天处理低优先级问题,却让一个严重问题等着。一个简单的顺序很管用:
- 先读完每一个严重和高问题。对每一个,读攻击场景并做出判断:属实、不属实,或需要更多上下文。
- 当天就修复属实的严重问题。如果修复需要时间,先加一个临时缓解措施,比如关闭该端点或收紧某项校验。
- 对需要上下文的问题,去核实缺失的那一块:是否已有中间件、行级策略或某项配置阻止了它?把答案写下来。
- 把高问题排进当前迭代,把中问题放进待办,把低和信息类问题攒成一次加固处理。
- 当一个问题不属实时,记录原因。这条记录能让下一个人不必再调查一遍。
请为每个问题指定一位负责人。由整个团队共同负责的问题,往往最后谁都不负责。
问题浏览器与导出
当你积累了若干次审计之后,问题浏览器会比单份报告更好用。它会列出跨审计的问题,并按严重程度、CWE 和仓库筛选。按 CWE 筛选尤其有用:如果同一个弱点出现在三个仓库里,通常说明存在一个共用模式或缺了一个辅助函数,而修复这个模式比逐个修复实例更省事。
问题可以从浏览器导出为 CSV,便于导入任务跟踪工具或电子表格。单份报告可以导出为 Markdown,它在拉取请求描述、内部 wiki 或发给负责修复的外包的消息中都很好读。
重新审计以确认修复
修复在你核实之前都不算完成。合并之后,请对同一个仓库运行一次新的审计。每份报告都可以与上一次审计对比,于是你能看到哪些问题消失了、哪些还在,以及是否出现了新问题。真实问题被修复后风险评分应当下降;如果没有,请看对比结果找原因。
请保持对比的公平。如果第一次审计是部分快照,而第二次读取了不同的文件,那么差异既反映修复也反映覆盖范围。审计次数会消耗你的月度额度,所以通常值得攒上几个修复再重新审计,而不是每次提交后都重跑一遍。
报告覆盖不到的内容
了解边界有助于你补上缺口。审计读取的是你的源代码;它不会扫描依赖中的已知漏洞版本,所以请同时保留一个依赖扫描器,比如包管理器内置的那个或 GitHub 提供的。审计看不到部署时的配置、仓库之外的基础设施,以及被跳过的文件。而且和任何审查者一样,无论是人还是 AI,审计也可能出错:证据和置信度的存在,就是为了让你能快速核实它,而不是全盘轻信。
这样使用之后,一份报告就变成了一张简短、有优先级、附带证据的改动清单。修好严重的,核实不确定的,重新审计,然后看着评分变化。