一个漏洞定位模型,连续三次找对文件。我把同一个仓库换成修复后的版本,它又连续三次报了同一个文件。
这下就尴尬了:只放前半段,是一段漂亮的本地 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 也只覆盖另一个模型空闲常驻,别据此安排同时推理。
公开材料可从 模型仓、基准仓 和 技术报告 查起。本文本地数字来自上述日期的复现记录,公开链接说明模型与任务来源,不冒充本地实验原始日志。
自己复测时,按这个顺序来:
- 找同一案例修复前后的快照,确认补丁处理的目标漏洞。
- 固定模型、提示词、采样参数和工具环境,给两边同样的读取机会。
- 保留“未发现目标漏洞”的提交出口,记录最终工具提交,别只看解释写得像不像。
- 分开统计目标文件命中与修复版正确退出,再扩展到不同仓库和漏洞类型。
- 冷启动、预热后的生成速度、完整流程耗时分开报;做取舍时加上复核误报花掉的时间。