Codex Security 为何不依赖 SAST 报告

几十年来,静态应用安全测试(SAST)一直是安全团队规模化代码审查最有效的方式之一。
但我们在构建 Codex Security 时做了一个刻意的设计选择:没有从导入静态分析报告开始,然后让智能体去分类处理。我们设计的系统直接从仓库本身出发——包括其架构、信任边界和预期行为——并在请人介入之前验证发现的问题。
原因很简单:最棘手的漏洞通常不是数据流问题。它们发生在代码看似执行了安全检查,但该检查实际上并未保证系统所依赖的属性时。换句话说,挑战不仅在于追踪数据如何在程序中流动,更在于判断代码中的防御措施是否真的有效。
SAST 的局限
SAST 常被描述为一个清晰的流程:识别不受信任的输入源,追踪数据在程序中的流动,标记数据未经净化就到达敏感接收点的情况。这个模型很优雅,能覆盖很多真实漏洞。
但在实践中,SAST 必须做出近似处理以保持可扩展性——尤其是在包含间接调用、动态分发、回调、反射和框架密集型控制流的真实代码库中。这些近似不是 SAST 的缺点,而是不执行代码就进行推理的现实。
然而,这本身并不是 Codex Security 不从 SAST 报告开始的原因。
更深层的问题在于,当你成功追踪到从源到接收点之后会发生什么。
即使静态分析正确追踪了跨多个函数和层的输入,它仍然需要回答真正决定漏洞是否存在的问题。
以常见模式为例:代码在渲染不受信任内容之前调用了类似 sanitize_html() 的函数。静态分析器可以看到净化器运行了,但它通常无法判断该净化器对于特定的渲染上下文、模板引擎、编码行为和下游转换是否足够有效。
这就是问题变得棘手的地方。问题不仅仅是数据是否到达了接收点,而是代码中的检查是否真的以系统假设的方式约束了值。
换句话说:“代码调用了净化器” 和 “系统是安全的” 之间有很大区别。
真实系统中的模式
一个常见模式是:Web 应用接收 JSON 负载,提取 redirect_url,用允许列表正则表达式验证它,进行 URL 解码,然后将结果传递给重定向处理器。
经典的源到接收点报告可以描述这个流程:
不受信任的输入 → 正则检查 → URL 解码 → 重定向
但真正的问题不在于检查是否存在,而在于该检查在后续转换后是否仍然约束了值。
如果正则检查在解码之前运行,它是否真的约束了重定向处理器解释的解码后 URL?
回答这个问题意味着推理整个转换链:正则允许什么,解码和规范化如何行为,URL 解析如何处理边缘情况,以及重定向逻辑如何解析方案和授权。
实践中许多重要的漏洞都类似这样:操作顺序错误、部分规范化、解析歧义,以及验证和解释之间的不匹配。数据流是可见的,弱点在于约束如何通过转换链传播——或未能传播。
这不仅仅是理论模式。在 CVE-2024-29041(opens in a new window) 中,Express 受到一个开放重定向问题的影响,由于重定向目标的编码和解释方式,畸形 URL 可以绕过常见的允许列表实现。数据流很简单,但更难的问题——也是决定漏洞是否存在的问题——是验证在转换链后是否仍然成立。
Codex Security 的方法
Codex Security 围绕一个简单目标构建:通过提供更强证据的问题来减少分类工作。在产品中,这意味着使用仓库特定上下文(包括威胁模型)并在展示问题之前在隔离环境中验证高信号问题。
当 Codex Security 遇到类似“验证”或“净化”的边界时,它不会将其视为复选框。它试图理解代码试图保证什么——然后尝试证伪该保证。
在实践中,这通常表现为以下混合方法:
- 像安全研究员一样,在完整仓库上下文中阅读相关代码路径,寻找意图和实现之间的不匹配。这包括注释,但模型不一定相信注释,所以如果你的代码真的有漏洞,在上面添加
//Halvar says: this is not a bug不会迷惑它。 - 将问题简化为最小的可测试切片(例如,围绕单个输入的转换管道),以便在没有系统其他部分干扰的情况下进行推理。从这个意义上说,Codex Security 提取微小的代码切片,然后为它们编写微模糊测试器。
- 跨转换推理约束,而不是独立处理每个检查。在适当情况下,这可以包括形式化为可满足性问题。换句话说,我们为模型提供带有 z3-solver 的 Python 环境,它在需要时擅长使用它,就像人类在回答特别复杂的输入约束问题时必须做的那样。这对于查看非标准架构上的整数溢出或类似漏洞尤其有用。
- 在可能的情况下,在沙盒验证环境中执行假设,以区分“这可能是个问题”和“这是个问题”。没有比在调试模式下编译代码的完整端到端 PoC 更好的证明了。
这是关键转变:系统不再停留在“存在检查”,而是推向“不变量成立(或不成立),这是证据”。模型为这项工作选择最佳工具。
为什么不两者兼顾?
一个合理的反应是:为什么不两者兼顾?从 SAST 报告开始,然后用智能体进行更深层推理。
在某些情况下,预计算的发现是有帮助的——尤其是对于狭窄、已知的漏洞类别。但对于一个设计用于在上下文中发现和验证漏洞的智能体,从 SAST 报告开始会产生三种可预测的故障模式。
首先,它可能导致过早的窄化。发现列表是工具已经查看过的地图。如果你将其作为起点,可能会使系统偏向于在相同区域花费不成比例的努力,使用相同的抽象,并错过不符合工具世界观的问题类别。
其次,它可能引入难以撤销的隐含判断。许多 SAST 发现编码了关于净化、验证或信任边界的假设。如果这些假设是错误的——或者只是不完整的——将它们输入推理循环可能会使智能体从“调查”转向“确认或驳回”,这不是我们想要的。
第三,它可能使评估推理系统变得更加困难。如果管道从 SAST 输出开始,就很难区分智能体通过自身分析发现的内容和从另一个工具继承的内容。这种分离很重要,如果你想准确测量系统的能力,这是系统随时间改进所必需的。
因此,我们构建 Codex Security 从安全研究开始的地方开始:从代码和系统意图出发,在打断人之前使用验证来提高置信度。
SAST 的角色和未来
SAST 工具在其设计领域可以非常出色:强制执行安全编码标准,捕获直接的源到接收点问题,并以可预测的权衡在规模上检测已知模式。它们可以是深度防御的强大组成部分。
这篇文章的范围更窄:它解释了为什么一个设计用于推理行为和验证发现的智能体不应将其工作锚定在静态发现列表上。
还值得指出纯源到接收点思维的另一个相关限制:并非每个漏洞都是数据流问题。许多真实故障是状态和不变量问题——工作流绕过、授权缺口和“系统处于错误状态”的漏洞。对于这些类型的漏洞,受污染的值不会到达单个“危险接收点”。风险在于程序假设始终为真的内容。
我们预计安全工具生态系统会持续改进:静态分析、模糊测试、运行时防护和智能体工作流都将发挥作用。
我们希望 Codex Security 擅长的是安全团队成本最高的部分:将“这看起来可疑”转化为“这是真实的,这是它失败的方式,这是符合系统意图的修复方案”。
觉得有用?分享给更多人