
最近安全圈有个消息挺有意思:Linux 内核维护者开始收到 LLM 生成的安全报告,115 票热度,评论区吵成一锅粥。大多数人在争论这些报告是不是噪音,但我更在意一个没人提的问题——漏报。
抱着这个疑问,我决定在自己代码上跑一遍同样的流程,结果比我想的还刺激。
找了三段生产代码:Next.js 的 webhook 处理器、2021 年写的 auth 模块(那时候刚转开发,代码质量你懂的)、还有一个 Railway 环境变量包装器。用的提示词极其简单,就是让 LLM 扮演安全工程师,只列漏洞,不解释概念,不废话。
丢给 Claude Opus 4 和 GPT-4o 跑了一遍,结果很有意思——两个模型找到了相同的东西,但也都漏掉了同一件事。
Claude 在我 webhook 处理器里标出三个问题:
console.log(req.body) 可能在某些请求里打敏感数据——真的,我没注意到。GPT-4o 找到同样的三个,外加一个误报:说我用 Math.random() 生成会话 ID,其实那玩意是用于内部日志关联 ID 的,跟会话半毛钱关系没有。
三个真实发现,一个误报,看起来挺靠谱对吧?
那个 2021 年写的 auth 模块里,有一个容易受到时序攻击(timing attack)的令牌比较逻辑:
// 这行代码看起来完全正常——但其实有安全漏洞
function validateToken(receivedToken: string, expectedToken: string): boolean {
// ❌ 易受攻击:直接字符串比较
return receivedToken === expectedToken;
// ✅ 正确做法:常量时间比较
// return crypto.timingSafeEqual(
// Buffer.from(receivedToken),
// Buffer.from(expectedToken)
// );
}
两个模型都没标记它。一个都没有。
为什么?因为代码"看起来对"。函数返回布尔,比较两个字符串,命名清晰——快速扫代码的人和快速扫代码的 LLM 一样,直接就过去了。
当 LLM 给你三个真实漏洞,你的第一反应是"好,现在我清楚我的问题了"。但时序攻击漏洞还在那儿,隐形的,带着"AI 已审查"的章。
这就是我觉得最要命的地方:LLM 安全报告的危险不在于产生噪音,而在于产生信心。
假阳性你还能扔掉,顶多浪费点时间。假阴性——LLM 没看到的漏洞——给你一个更可怕的东西:一种"已经审过了"的错觉。你带着这个错觉就部署了。
测多了之后规律就出来了:
看得好的:
看得差的:
最后一类我觉得最危险。安全审计也好、代码审查也好,LLM 很擅长评估它面前的东西,不擅长推理缺失的部分和系统涌现行为。
时序攻击是在单个文件的上下文里漏的。如果我把完整调用链——从端点到校验——一起给它,也许能发现。也许。
"没发现什么" ≠ "什么都没有",它只是"在它处理的内容里没发现什么"。这个区别很重要。
没有上下文时,LLM 假设一个通用威胁模型。不知道对手是脚本小子还是有资源有时间支撑的团队。提示词故意保持中立——这也是我的失误之一。
GPT-4o 和 Claude 发现了不同的东西,这本身就说明两者都没有完整覆盖。拿它们当独立查询跑,再对比输出,比只信一个靠谱得多。
webhook 处理器和 auth 模块需要不同的提示词,本地上下文变了,相关漏洞也变了。
LLM 能替代真正的渗透测试吗?
不能。LLM 能对静态代码做第一轮检查抓住明显问题,渗透测试涉及执行上下文、系统交互、权限提升、运行时行为分析。LLM 在渗透测试之前有用,不是代替它。
向 Linux 内核这种开源项目发 LLM 生成的安全报告合理吗?
如果报告经过人工核实、描述的是真实漏洞,有价值。如果是不经人工整理的原始 LLM 输出直接发给已经满负荷的维护者,那就是带着真实人力成本的噪音。问题不在于 LLM 生成了它,而在于人类核实这个环节从链条里消失了。
在 CI/CD 里自动化 LLM 安全审查值不值?
要谨慎。逐 commit 审查 token 成本涨得很快。对于自动 CI,最佳做法是选择性触发:只审查涉及认证、密钥处理、输入校验的文件,而不是每次 push 都全量审查 diff。
LLM 作为第一层审查确实有用,比不审强。它在我代码里发现了三个真实问题,都是我一直拖着没改的。
但我不买账的是"LLM 审查 = 足够"这个叙事,更不买账"等同于专家人工审查"。这个叙事存在是因为它方便——对供应商方便,对有 deadline 的团队方便,对任何想要"有安全流程"这个感觉但不想真花成本做好的人方便。
模型漏掉的时序攻击并不算冷门,是有文档记录的已知模式,一行代码就能修。它们漏掉是因为它隐含在行为里,而不是显式在语法里。
诚实的权衡是这样的:LLM 安全报告给你可见内容的覆盖范围。不可见的依然不可见——而且现在它带了个"已审查"的戳。
这个戳——这才是让我不舒服的地方,也是我为什么要自己做这个实验,而不是坐在那儿接受第一轮让人安心的审查结果。
如果你做的东西有真实攻击面——公共端点、令牌处理、用户数据——别让 LLM 安全报告成为终点,当起点用。差异比看起来大得多。
原文:https://juanchi.dev/en/blog/llms-generating-security-reports-ran-prompt-on-my-own-code