返回博客

2026.09.19

漏洞文件三次全找对,修好后三次还报它——这个安全模型该不该用?

一次 Antares-1B 本地复现:同一仓库的修复前后对照,把定位能力和判断安全的能力拆开,也划出了小模型适合做候选排序的边界。

AIbenchmarkingsecurity

一个漏洞定位模型,连续三次找对文件。我把同一个仓库换成修复后的版本,它又连续三次报了同一个文件。

这下就尴尬了:只放前半段,是一段漂亮的本地 AI 演示;把后半段接上,我连“它知道什么时候该闭嘴”都没法保证。

先说取舍:我会继续测试它做候选文件排序的价值,暂时不会让它决定代码有没有漏洞。想拿走看榜单的方法,跳到第 2 节;复测清单在第 4 节。

1. 文件找对了,为什么我还不敢信

下面是 2026-07-22 的历史实跑记录,今天没有重新运行模型。对象是 Cisco Foundation AI 的 Antares-1B,使用 MLX 在 M1 Max 64GB 上运行 BF16 权重。MLX 是 Apple Silicon 上的机器学习框架;这里用的是本地模型,没有拿远端大模型替它答题。

任务取自公开的 VLoc Bench。这个基准让模型在仓库里找漏洞所在的文件。本次只选了 express-xss-sanitizer 的一个递归相关案例:递归就是函数不断调用自己,碰到过深或循环的输入,如果没有边界,就可能把调用栈耗尽。

给模型的工具也很朴素:搜索仓库、读文件,再提交判断。模型仓自带的执行循环接上本地后端,采样温度沿用官方的 0.3。它可以翻代码,不能改代码。

原版的三次运行,全都指向 lib/sanitize.js,理由也对:遍历对象与数组时缺少深度或循环检测。到这里,看起来挺好。

然后换修复版。还是三次,还是那个文件。

同一案例的快照 本地运行结果 这一侧能说明什么
有目标漏洞的版本 3/3 找到目标文件 这一个案例能定位
已修复目标漏洞的版本 3/3 仍提交该文件 这一个对照没能正确退出

最扎眼的是其中一次:它已经读到 MAX_DEPTH=100 和深度计数,解释里还承认深输入会抛错,最后照样提交漏洞文件。代码读到了,提交动作却跟自己的解释打架。

这让我怀疑它有“既然让我找,那就必须交一个”的倾向。但训练如何导致这个倾向,本次没有做因果实验。能站住的证据只有行为:修复前后,最终提交没有随证据改变

给这份小样本算两笔账就够了:

  • 目标文件命中比例 = 正确定位次数 ÷ 有漏洞版本运行次数 = 3 ÷ 3。
  • 修复版正确退出比例 = 正确报告未发现目标漏洞次数 ÷ 修复版运行次数 = 0 ÷ 3。

两个分母都要留着。只报第一个,后半段的问题就被整块藏起来了。

2. 看到 File F1,先问题目保证了什么

公开报告里有一个很容易被拿错用法的数字:File F1 为 0.209。根据当时核查的基准口径,它对应 500 个保证存在漏洞的任务上的文件级 macro-F1,也就是先逐任务评分,再把各任务分数平均。

F1 把“报出的文件有多准”和“该找的文件漏了多少”合在一起。公式写开是:F1 = 2 × P × R ÷ (P + R),其中 P 是报出的文件里有多少报对了,R 是目标文件里找回了多少。

别急着把小数换成一句“能发现多少漏洞”。0.209 不能直接读成漏洞召回率,更不能回答“给它一份已经修好的代码,会不会乱报”。保证有漏洞的题,根本没把后一个问题摆上桌。

我这次的小对照刚好能把这个盲点照出来:原版 3/3 命中,修复版 0/3 正确退出。定位题的好成绩,无法替拒报题作答。

以后看到别人展示漏洞模型的成绩,我会先找三个东西:有没有修复版对照;两边是否用了同一套提示词和工具;最终是否允许提交“没有发现”。缺了这些,演示能证明的范围就停在找文件,别往安全裁决上加戏。

也别反过来拿我的三次误报宣布模型处处不行。重复跑同一个案例,增加的是这一个案例的重复观察,不会自动增加仓库、语言和漏洞类型的覆盖。修复了已知目标漏洞,也不等于证明整个仓库绝对安全。

3. 我自己的速度数字也翻过车

如果你准备本地试它,还得小心另一张看起来很像证据的表:速度。

最初冷启动冒烟测试只生成 21 个 token,记录里 decode 是 12.39 tok/s。token 可以粗略理解为模型吐出的文本碎片;decode 速度量的是生成阶段吐得多快。这个数字把我带偏了,差点去怪另一个常驻模型占着内存。

后来固定 1,932-token 输入、固定生成 256 token,先预热,再各跑 7 次。两组生成文本的哈希完全相同,也就是输出字节一致。一组让小模型独占机器,另一组只让一个约 22GB 的模型空闲常驻,没有向后者发请求。

条件 decode 中位数
独占 76.280 tok/s
另一个模型空闲常驻 75.939 tok/s

把收益摊开算:(76.280 − 75.939) ÷ 75.939 ≈ 0.45%。这次测到的差距很小,没理由把速度问题甩给那个空闲模型。它也不能代表两个模型同时忙起来的情况。

早先的短冷跑混入了首次执行的固定开销。用它预测预热后的持续生成速度,会差很远。反过来,用约 76 tok/s 预测从点击开始到拿到漏洞判断的等待,也不靠谱:读代码、工具往返和越来越长的输入都要时间。

干净窗口里重跑完整流程,有漏洞版耗时 14.8–36.0 秒,修复版 16.3–24.9 秒。速度好了,质量结论没变,两边仍各 3/3 提交同一个文件。快一点把误报交上来,并没有替我省掉复核。

4. 要不要装,先把复测做成一对

我愿意继续试的是一个窄用途:已有告警或已知漏洞线索时,让它帮忙缩小阅读范围,最终判断另行核实。这次记录还没证明它比传统搜索或其他排序方法更划算,所以“候选排序”也只是下一步值得测的用途。

缺的东西摆明:只有一个仓库的一个案例,没有跨语言、跨漏洞类型的成对评测;没有总体误报率估计;没有人工复核时间的收益对照。速度 A/B 也只覆盖另一个模型空闲常驻,别据此安排同时推理。

公开材料可从 模型仓基准仓技术报告 查起。本文本地数字来自上述日期的复现记录,公开链接说明模型与任务来源,不冒充本地实验原始日志。

自己复测时,按这个顺序来:

  • 找同一案例修复前后的快照,确认补丁处理的目标漏洞。
  • 固定模型、提示词、采样参数和工具环境,给两边同样的读取机会。
  • 保留“未发现目标漏洞”的提交出口,记录最终工具提交,别只看解释写得像不像。
  • 分开统计目标文件命中与修复版正确退出,再扩展到不同仓库和漏洞类型。
  • 冷启动、预热后的生成速度、完整流程耗时分开报;做取舍时加上复核误报花掉的时间。