让 LLM 先猜开发者的假设再找矛盾,Creed 在 50 个新 CVE 上召回率达 78%
LLM-based Code Auditing by Inferring and Evaluating Developer Assumptions
Junming Liu, Marcel Böhme
cs.CR, cs.SE
2026-10-12
Creed 让 LLM 推断函数里开发者的隐含假设,再判断其是否合理、何时被打破;在 50 个新 CVE 上召回 0.78,高于最强基线 10 个百分点。
这篇在解决什么
传统静态分析找 bug,靠的是把「模式」写死:比如某个指针被判空过,后面又不判空就解引用,算违反了开发者的信念。这类方法只适用于能用语法模式表达的缺陷。现实里很多漏洞要靠领域语义才看得出来:认证函数对「用户不存在」和「密码错误」返回同一个错误码,本意是防用户枚举,但多出来的一次哈希计算会让两种失败的响应时间不同,留下计时侧信道。这种洞,PDG(程序依赖图)上找不到通用模式。
论文在 CVEfixes 里随机看了 50 个近期漏洞,发现 40 个是语义类,其中 21 个无法表达成通用静态分析模式。另一个老问题是评测:把函数级漏洞检测当二分类,已有工作指出并不成立,因为函数是否有漏洞常取决于调用者的上下文。
方法
Creed 把一位人类审计员的流程塞进一条 prompt,由 LLM 一次调用走完三步。
- 信念推断:先做两层动作识别。低层动作(如解引用指针)用来抓空指针之类的底层缺陷;整函数动作(如「取消支付」)用来抓授权缺失之类的高层缺陷。再对每个动作推断开发者默认成立的假设(belief),一个动作可对应多个信念。
- 信念评估:两种检查互补。sanity check 判断信念本身合不合理,不合理就必然有洞,且与上下文无关,例如「siteId 匹配就足以授权取消某笔支付」。violation check 针对合理的信念,推导它在什么条件下会被打破,例如两种失败路径响应时间不同。
- 漏洞报告:被标记的信念合并成若干 finding,每条写明根因和可利用的上下文条件,并回链到支持它的信念。
因为分析只在函数级进行,报告里的漏洞只叫「潜在」漏洞,上游代码可能已经缓解。把条件显式写出来,就是为了让人去核对。
评测上,论文提出两个指标。recall:至少有一条 finding 的解释与 CVE 描述、修复 commit 信息和补丁一致的漏洞占比。overhead:为确认一个预期漏洞,平均要读多少条 finding。匹配由 GPT-5.4 当 judge 判定,所有被判匹配的结果又人工复核。
结果
基准是 2025 年 9 月到 2026 年 3 月披露的 50 个 CVE 函数,覆盖 45 个项目、10 种语言、10 种漏洞类型。所有方法统一用 Claude Sonnet 4.6。
| 方法 | 匹配数 | Recall | Overhead | 每函数 token |
| RepoAudit | 1 | 0.02 | 8.0 | 54.6k |
| VulTrial | 21 | 0.42 | 3.3 | 17.3k |
| PrimeVul-CoTexp | 27 | 0.54 | 5.2 | 2.7k |
| LLM-Thinking | 34 | 0.68 | 11.3 | 3.9k |
| Creed | 39 | 0.78 | 7.9 | 8.5k |
- 成对评测(漏洞版对修复版)中,Creed 有 33 对是漏洞版命中、修复版不命中,是五者中最高。
- 只看每个函数前 2 条 finding,Creed recall 0.68,前 3 条升到 0.72,已超过任何基线读完全部 finding 的上限。
- 按类型:内存类 90%(10 个),语义类 75%(40 个)。21 个无法用通用模式表达的漏洞里命中 15 个,LLM-Thinking 是 12 个。计时侧信道只有 Creed 找到。
- 消融:去掉动作识别,recall 从 0.78 掉到 0.60;去掉 sanity 或 violation 检查,都掉到 0.66。
- 对每个函数只看第一条 finding 的人工检查,precision@1 为 0.74(37/50),其中 14 条是人工确认的非预期真漏洞。
- judge 与两位人工标注者在 50 条样本上一致 96%。
为什么重要
对做代码审计或安全 LLM 工具的人,有用的是思路:不要只让模型「找漏洞」,而是让它先写出代码背后的假设,再逐条质疑。同一个 backbone 下,这个结构比普通 CoT 和 thinking 模式多找出 5 个到 18 个漏洞(对 LLM-Thinking 多 5 个),单次调用的成本只有约 8.5k token。
评测上,「解释 + recall + overhead」的做法也可借用,它绕开了函数级二分类的上下文依赖问题。
不过收益是渐进的:对最强基线是 10 个百分点,代价是 overhead 比 VulTrial 高。
局限与存疑
- 基准只有 50 个函数,且样本经人工挑选以确认函数含根因,置信区间会很宽。论文没有给出重复运行的方差,Creed 用温度 0,LLM-Thinking 不可调。
- 评测用的 judge 是 LLM,虽有人工复核,但 recall 的判定标准是「解释与证据一致」,边界有主观成分。
- RepoAudit 只覆盖 28 个函数的语言、2 个在其检测范围内,基线很弱,0.02 的对比意义有限。
- 跨函数上下文缺失导致误报:13 个误报里 10 个是调用者或守卫 API 已缓解。
- 作者承认的边界:涉及应用自身安全策略的漏洞(如不能下载就不能分享文件)和开放条件的漏洞(危险替换字符串无穷多)抓不到。11 个漏报里 3 个没提取出相关动作,3 个需要应用专有知识。
- 论文提到换用 DeepSeek V4 Pro 作 backbone 仍最高,但未给出具体数字。
术语
- belief(信念):开发者写代码时默认成立的隐含假设,如「通用错误码能让攻击者分不清两种失败」。
- PDG:程序依赖图,记录语句间数据和控制依赖,传统静态分析常在其上匹配模式。
- user enumeration:通过响应差异判断某用户名是否存在的攻击。
- timing side-channel:靠响应时间差异泄露信息的侧信道。
- P-C:成对评测里漏洞版命中、修复版不命中的情形,说明报告确实由缺陷触发。
- LLM-as-a-Judge:用另一个 LLM 给输出打分或判定是否匹配。
原文与代码
社区讨论
相关论文
全部论文解读