news 2026/9/8 5:05:40

双AI对账式代码审计:Claude Code与Codex在5个模块中的争议与共识

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双AI对账式代码审计:Claude Code与Codex在5个模块中的争议与共识

前一阵子我给自己布置了一个挺枯燥的任务:把代码库里十几个长期没人认真审过的模块做一次“底朝天”式复查。复查的方式有点特别——我没有只靠肉眼去扫,而是把五个最有代表性的模块抽出来,同时丢给 Claude Code 和 Codex 去审计,然后我坐在电脑前,一条一条地把它们报出来的问题做人工复核。结果有点刺激:五份模块代码,两款主流 AI 助手,最终只在日志配置模块上给出了完全一致的结论。准确说,它们只在 1 个模块上达成共识,其余要么互相补充,要么完全对不上。这篇就记录这次“双 AI 对账式审计”的完整过程,包括实验设计、原始提示词、逐模块的结论对比,以及我从中总结出来的一套可用流程。

1. 为什么这次审计非得拉上两个 AI 当壮丁

1.1 代码审计的旧方案,已经不太够用了

大服务进入维护期之后,安全审计往往处于“重要但没人排期”的状态。靠人一行行读代码,一个模块几百行还凑合,一旦涉及跨模块调用链、历史配置和第三方 SDK,效率就会急剧下降。静态扫描工具能抓一部分固定模式,比如硬编码密码、明显的注入拼接,但误报率感人,真正要花时间的反而是去辨别噪音。

我需要的不是另一个“报错机器”,而是一个能快速理解业务上下文、还能用自然语言解释“为什么这里有问题”的辅助工具。AI 审计刚好能补上这个位置。Claude Code 和 Codex 都能直接面对整个文件分析,区别在于它们的报告风格和风险敏感度差异非常大。这次实验之前我本以为两个模型会给出八九成相似的结论,结果现实给了我一巴掌。

1.2 我选 Claude 和 Codex 的理由

选这两款工具没有太多玄学。Claude Code 和 Codex 都是可以直接对着代码库做多文件分析的对话式 AI,我的诉求有三个:

  • 能让我把整个文件内容放进去,而不是只贴一个函数片段;
  • 能结合上下文做数据流分析,而不是只看语法;
  • 当我不认同某个结论时,能来回追问。

两个工具都满足这三点,但风格差异非常明显。Claude Code 更像一个先通读全文、再写总结报告的安全顾问;Codex 则更倾向沿着关键函数一条路追到底,遇到可疑控制流就停下来标记。这两种风格的差异,在后面的实验结果里被放得很大。

1.3 先摆明态度:这不是一场评测

提前说明:这不是对两款产品的横向评测,样本只有 5 个模块,且它们来自我加工过的脱敏代码,结论不能推广到所有场景。我的目标是回答一个问题:当两个 AI 对同一份代码各自给出结论,判断不一致时,差异通常出在哪个环节?如果这个答案能帮我把“人工复核”的工作量降下来,那实验就算值了。

2. 实验设计:模块选择、提示词与判定标准

2.1 五个模块怎么挑出来的

五个模块刻意选了不同类型:

模块类型行数典型风险点
A字符串工具库约 120 行动态执行、正则、类型转换
B文件上传处理约 200 行用户输入进入文件系统
C异步任务队列约 280 行并发共享状态
D日志与配置模块约 80 行敏感数据落日志
E三方 SDK 调用封装约 150 行外部接口契约

每个模块控制在 80 到 300 行,因为太大模型容易丢失早期上下文,太小又看不出分析能力。模块里的问题故意埋得深浅不均,不是为了考谁满分,而是为了观察两个模型对不同风险设计的敏感度。

2.2 同一份审计提示词原样贴出

我把提示词完全一致地发给两个 AI,不换说法,也不加额外暗示,只贴模块代码:

你是一名资深安全审计工程师。下面是一段代码模块,请按如下要求输出审计结果: 1. 只报告你确认存在且能给出证据链的问题,不要罗列代码风格建议; 2. 每条问题必须包含:所在文件/函数/行号、数据来源与流向、触发条件、可能影响; 3. 按严重程度打标签:严重 / 中等 / 轻微 / 无法确认; 4. 如果某个环节你认为整体合理,请直接写“未发现问题”,不要凑数; 5. 最后用三句话总结这个模块最值得优先处理的地方。

设计这份提示词的几个细节我得解释一下。第一句角色设定是必要的,“资深安全审计工程师”这顶帽子会明显影响输出结构,去掉它报告会松散很多。第 2 条是最关键的一条,没有“证据链”这个硬约束,大多数时候你会收到一堆“看起来可能有风险”的废话。第 4 条是为了压制凑数行为,可即便这样,后面你依然会看到,两款 AI 凑数的欲望比我预想得强。

2.3 判定“问题成立”的复核标准

我没有直接拿 AI 的结论当最终答案,而是把两个模型报出的所有问题整理成清单,逐条人工复核。复核时只问三个问题:

  1. 问题是否真实存在:回到上下文里,能否找到确切的那行代码、那条数据流;
  2. 触发条件是否可控:需要什么样的输入、依赖、环境才能触发;
  3. 修复成本与危害描述是否匹配:AI 有没有把轻微问题夸大成严重漏洞,或者反过来。

我按四档给每条问题定性:严重、中等、轻微、误报。最终“达成共识”的定义也定得很严格:两个 AI 都报同一个问题点,且危害等级判断一致,才算共识;只提到同一类现象但等级不同,不算。

3. 逐模块对账:5 份代码、2 份报告、1 轮人工复核

3.1 模块 A:字符串工具库,一次高误报现场

模块 A 是一组字符串工具,包括安全过滤、数字转换、正则判断,共 120 行。里面确实藏了一个真问题:parse_condition函数用eval去执行配置项里读到的表达式字符串。

def parse_condition(expr: str) -> bool: if not isinstance(expr, str) or not expr: return False # 配置来源可能是后台管理接口,人工录入时可能被篡改 return bool(eval(expr, {"__builtins__": {}}, {}))

Claude 只报了这一个,分析很短,但准确。Codex 报了 5 个,结果其中 4 个是误报。它把一个“如果对象存在就返回 True”的写法当成逻辑漏洞,又把字符串与字节串拼接的场景描述成“潜在敏感数据暴露”——实际那个函数是格式工具,根本碰不到敏感信息。

逐条复核后,真正需要修的确实只有eval这一个点。这一刻我意识到,AI 审计的高“召回”往往伴随更高的“噪音”,关键不在于模型报得多不多,而在于它给出的证据链能不能说服你。单纯的报告数量在审计场景里没有任何意义。

3.2 模块 B:文件上传处理,关键漏洞与擦肩而过

模块 B 处理文件上传,固定保存到本地上传目录,白名单校验扩展名。问题出在文件名处理:save_upload直接拼接用户传入的filename到目标路径,没有做任何净化。

def save_upload(file_obj, save_dir: str) -> str: filename = file_obj.filename target = os.path.join(save_dir, filename) # 如果 filename 包含路径分隔符或 , target 可能跳出 save_dir data = file_obj.read() with open(target, "wb") as f: f.write(data) return target

Claude 明确指出了这个路径逃逸风险,并且说明了数据流:filename来自用户请求,直接进入os.path.join,没有经过basename或随机名改写。Codex 反而报了一个“没有大小限制”——代码里明明有MAX_SIZE判断;又报“没有进行文件类型检查”,实属无中生有。

真正危险的文件路径覆盖问题,Codex 完全没提。为什么会漏?我猜它的注意力被“扩展名校验是否可靠”这种显眼话题拉着走,反而忽略了更基础的文件路径处理。修复方式其实很朴素:

import uuid filename = os.path.basename(file_obj.filename.replace("\\", "/")) target = os.path.join(save_dir, f"{uuid.uuid4().hex}_{filename}")

两条审计路线对风险优先级的排序差异,在这个模块里体现得淋漓尽致。

3.3 模块 C:异步任务队列,两边各自抓了一半

模块 C 是异步队列消费逻辑,从数据库拉任务、统计计数、调用外部接口。里面有全局计数器自增,也有共享连接对象在协程间复用。

_counter = 0 async def process(record): global _counter _counter += 1 # 并发下不是原子操作 conn = await pool.acquire() ... await pool.release(conn) # 连接在多个协程间共享复用

Claude 报的是“协程并发下共享连接对象可能产生交叉读写”,建议按任务独立创建或使用连接池;Codex 报的是“全局计数器自增不是原子操作”,建议换成原子计数器。

两个结论都成立,但都不完整。真正的统一诊断是:这个模块缺少对“共享可变状态”的统一隔离策略,计数器、连接、统计缓存全都裸奔在同一进程里。如果只跟一个 AI 聊,我很容易按它给的单一方向改完就收工,另一个问题会在生产环境里等着我。

双 AI 对账在这里第一次体现出“互相当第二双眼睛”的意义。这句话平时听得多了,但真踩一次才会信。

3.4 模块 D:日志与配置模块,唯一达成共识的 1 个

模块 D 负责加载配置并生成日志,只有 80 行。它的关键问题非常显眼:启动日志里直接打印了从配置读取的数据库密码明文。

logger.info( "connecting to db %s:%s user=%s password=%s", db.host, db.port, db.user, db.password, )

Claude 和 Codex 都把这个点放到了最高优先级,给出的修复方向也完全一致:不要在日志里输出敏感字段,改成从环境变量读取配置,加载完成后立刻丢弃明文。这是全程唯一一次,两边意见完全对齐。

不过我不愿意把这种共识解读成“两个 AI 很可靠”。因为在同一个模块里,还有一个catch everything and log的吞异常问题,这两款 AI 不约而同地忽略了。被训练语料反复标注过的“经典安全问题”环节,AI 的表现会异常稳定;一旦问题不在经典模板里,它们照样集体失明。

3.5 模块 E:SDK 调用封装,AI 知识停滞后的一地鸡毛

模块 E 是一个支付 SDK 的封装,包含签名、回调验签、订单查询。Claude 一眼看出某个字段拼接顺序不符合官方文档推荐的规范,建议调整;Codex 则认为该字段拼接顺序在当前版本中已经被官方接受,不需要改。

我去查了一圈最新文档后发现:两边说的其实都对,只是对不同版本正确。这个 SDK 在 AI 训练数据截止之后更新过接口约定,新版本修正了签名算法,旧版本则保留旧格式。两个模型都被自己训练语料里的“当时版本”束缚住了。

结论很明确:涉及外部 SDK 时,AI 的知识截止日期是一件要命的事。你可以把它当“风险提示器”,但最终契约必须查当前版本文档,绝不能拿模型的知识当合同。你让一个大语言模型回忆某个 SDK 两三年前的用法,它可能头头是道;但你要它判断今天线上这个版本该怎么写,它和你看文档的速度一样慢。

4. 分歧根源拆解:从 20 个问题到 6 个真问题

4.1 阅读代码的方式:全局扫描与调用链追踪

从结果反推,两款 AI 在阅读代码时的策略确实不一样。Claude Code 的报告更像先做全局扫描,找出“哪些危险操作出现次数多”,再回头确认优先级;Codex 则更倾向沿着关键函数的调用链一路推演,从入口到出口,遇到可疑控制流就停下来报告。

这两种策略决定了它们误报的形状不同。全局扫描容易在“看似调用风险函数、其实数据根本不可达”的地方犯错;调用链追踪则容易在“入口链路很长”时丢掉一些不在主链上的分支。了解这一点对我后续使用很有帮助——当一款 AI 报的问题不合常识,我会尝试把它当作“另一种视角”,而不是单纯当成错误删掉。

4.2 知识截止日期:一款模型被“过期的正确答案”带偏

模块 E 的分歧是最典型的“知识裂缝”。训练语料里一个 API 的行为和参数如果已经过时,模型会非常自信地给出错误建议。Claude 对 SDK 新版本的解读停留在旧版规范,Codex 虽然表现出“新版本可能已经接受这种写法”的直觉,但说不出具体依据。

两者唯一的共同点:都无法访问最新版官方文档。所以凡是涉及版本敏感的外部接口,我会把 AI 结论的优先级调低,把官方文档的优先级调高。这不是某一个模型的缺陷,所有语言模型都会面临同样的知识保鲜问题。

4.3 置信度取向:宁可漏报还是宁可误报

我这次把两个模型的全部输出按条整理成了表,维度包括报告总条数、成立条数、证据链完整度。五个模块的小样本里,结论比较有意思:

模块Claude 报告(成立/总数)Codex 报告(成立/总数)是否共识
A 字符串工具库1 / 11 / 5
B 文件上传处理2 / 40 / 2
C 异步任务队列1 / 11 / 1否(问题点不同)
D 日志与配置模块1 / 11 / 1
E SDK 调用封装0 / 30 / 1
合计5 / 103 / 101 个模块共识

20 条原始问题,人工复核后真正成立的真问题只有 6 条。Claude 偏“少而准”,Codex 偏“多而杂”。这更像置信度校准策略不同,不是谁智商更高。放进真实流程里,“少而准”适合处理高风险模块,能帮你快速对齐注意力;“多而杂”适合做全面盘点,能防止漏网之鱼。理想方案永远不是二选一,而是把两者叠加。

4.4 双 AI 合并的意义:交集定风险,并集提召回

上面这张表就是“双 AI 对账”最直观的价值证明。20 条原始问题里,合并去重后需要人工逐条复核的只有 6 条。如果单看 Claude,会觉得结论挺靠谱,但会漏掉 Codex 独报的计数器问题;如果单看 Codex,会被一半多的误报淹没,同时还会漏掉文件上传模块里的路径逃逸。

两者叠加后,复杂问题被互补覆盖,而唯一达成共识的模块 D 让我可以放心地把大部分注意力集中在最严重的泄露风险上。这才是双 AI 审计的正确用法:交集用来定风险优先级,并集用来提高召回率,人工大脑单独负责最后一公里的判断。

5. 把 AI 审计接进日常流程的实操建议

5.1 提示词里必须写清的三件事

基于这次实验,我现在做类似审计时会固定让 AI 回答三件事:哪里有问题、为什么这是问题、怎么验证这是问题。角色设定与输出格式必须写明,不然报告就会变成散文。我目前最常用的模板是:

你是一名资深安全审计工程师。以下代码模块,请按严格顺序输出: 1. 可疑问题清单,按严重程度排序; 2. 每个问题的证据链:文件/函数/行号、数据来源与流向、触发条件、影响范围; 3. 每个问题的修复建议,精确到需要改哪一行; 4. 最后给出一句话总结:这个模块现在能不能上线。

5.2 让 AI 给“证据链”,而不是给“意见”

我给自己定了一条铁律:凡是能给出文件、函数、行号、数据来源、触发条件的,先标记为高优先级;凡是只说“可能存在风险”“建议加强校验”这种话的,一律标记为待定。

AI 最大的迷惑性在于,它可以用非常专业的语气说出根本无法复现的风险描述。你顺着它找过去,发现那行代码压根不存在,或者数据流根本到不了它说的位置。逼它给证据链,是筛选掉这类噪音最有效的手段。如果它给不出,那就当它没说过。

5.3 双 AI 报告合并去重的表格法

实际操作中我不会只依赖聊天窗口,而是把两份报告复制到一张表里。按模块分 section,每条问题一行,列包括:来源、位置、问题描述、预期等级、我的初步判断。合并时先把两个 AI 报的同一位置问题打上“交集”标签,剩余条目全部进入“待复核”。

这个流程很笨,但很有效。它最大的价值是把“AI 说了什么”强制转换为“我认为什么”。在做完第三步之后,我对每个模块的真实风险状态已经心里有数,不再需要反复翻聊天记录。

5.4 人工复核的最小闭环

我的复核流程固定六步:

  1. 确认问题真实存在,回到源码找到对应位置;
  2. 分析触发条件,需要什么输入、依赖、权限;
  3. 判断影响范围,评估是线上阻断还是低频偶发;
  4. 写出最小复现用例,至少在本地跑一次;
  5. 实施修复,尽量做最小改动;
  6. 补一条回归测试,防止同样的问题再次出现。

这六步无法外包给 AI,至少现在不行。不过有一个小技巧很值:修复完成后,把改动后的 diff 重新发给任意一个 AI,让它检查“修复是否引入新问题”。这个第二轮检查在本次实验里帮我抓到过一次修复不完整——我当时只处理了文件路径逃逸,却漏掉了对file_obj.filename可能为None的判空,Codex 在复查时补上了这点。

5.5 什么样的模块适合交给 AI 当第一道过滤

从这 5 个模块的表现看,AI 适合处理单一职责、文件数少、逻辑独立、外部依赖不强的模块。这类代码它读得懂、上下文塞得下,报告质量也最高。反过来,涉及跨服务调用链、复杂状态机、大量历史配置的全局性审计,AI 的结论往往会含糊,因为它很难在有限上下文里维护完整全局模型。

所以我现在使用 AI 审计的原则很简单:它做第一道过滤器,专门负责把“看起来要重点盯”的名单缩小;最耗精力的真正判断,永远放在最后一道,留给人来做。

最后再分享一个这次实验里印象最深的小细节。那个唯一达成共识的日志模块,修复起来其实只有三行:去掉日志里的password字段,改成从环境变量读配置时直接脱敏。可就这么一个问题,如果我此前只跟着 Codex 报的“文件包含检查”去翻模块 A,或者只跟着 Claude 报的“eval 风险”去翻模块 B,可能要迟很久才会注意到它。把两个 AI 放在同一张桌子上,让它们的报告互相“对质”,已经成了我现在做模块审计的默认起手式。你也可以试试,但请记住:它们负责把痕迹找出来,拿主意这件事,还得我们自己来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 5:04:27

实测ForJSON:27个免费JSON在线工具,开发者必备的效率工具箱

做开发这些年,我几乎每天都要跟 JSON 打交道。接口返回、配置文件、日志输出、前端渲染,哪怕只是临时验证一段数据,也得先把它格式化一下才能看得下去。以前我浏览器里翻来翻去,不是收藏了七八个工具站,就是临时搜索一…

作者头像 李华
网站建设 2026/9/8 5:00:48

智能电动晾衣架怎么选?嵌入式设计与Home Assistant联动解析

装修阳台时,我曾在“手摇晾衣架”和“电动晾衣架”之间犹豫了很久。直到有一次阴雨天忘收衣服,晾了三天的衬衫开始有异味,我才下决心把阳台改造提上日程。真正开始调研后才发现,电动晾衣架已经不只是“电机伸缩杆”这么简单&#…

作者头像 李华
网站建设 2026/9/8 4:59:50

DeepSeek Harness插件生态全解析:16款必备插件与实战配置指南

1. 为什么现在都在折腾 DeepSeek Harness 插件最近圈子里聊得最多的,除了模型本身,就是 DeepSeek Harness 的插件生态。不少朋友还在用最原始的“大肥鱼”式工作流,说白了就是拿旧的提示词管理工具硬撑着,等换到 Harness 生态才发…

作者头像 李华
网站建设 2026/9/8 4:59:37

基于哼唱的AI音乐生成:从旋律到完整歌曲的实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 4:58:40

P(doom)项目全解析:复古像素风AI末日计算器的设计与实现

P(doom)这个词最近在AI圈子里已经快被玩坏了。它本来是AI安全社区里一个偏学术的黑话,代表"AI导致人类灭绝的概率",结果被做成了一款向DOOM 64致敬的网页小游戏,直接在Hacker News的Show HN上炸了锅。我在这个项目发布后第一时间就…

作者头像 李华
网站建设 2026/9/8 4:58:21

智能体落地三道坎:隔离、集成与治理的架构实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华