独立的对抗性代码审查
本页由 AI 从英文翻译,尚未经过母语人士审校;如有出入,以英文原文为准。 阅读英文原文
代码可以运行得完美无缺,却仍然让人得以窃取资金、读取私密数据或夺取控制权。
CounterProof 是一个独立团队,在别人之前尝试攻破你的代码。对于我们报告的每一个问题,我们都给出证据:它在代码中的位置,我们如何检查它,以及还有哪些不确定之处。你会得到一份签名报告,可以与客户、保险公司、投资者和监管机构分享。
一个模型检查自己的工作,不是独立审查。
获取独立审查 →没有人购买代码审查。人们购买的是它能为你打开的东西。
你读到这里,并不是因为你一觉醒来就想要一份安全评估。是有什么东西在要求你提供证据。
这四方中有三方从不接受你对自己代码的自述;他们购买的正是独立性,而这恰恰是任何团队都无法为自己的工作提供的属性。第四方,即监管机构,往往会接受你的自我评估,然后要你为其背后的每一份记录负责。无论哪种情况,证据都必须站得住。这正是我们产出的东西。
发现变得廉价,证明变得艰难。
每次委托都会在一个持久的委托标识符(CPR-YYYY-NNN)下产出一份 CounterProof 评估,你的维护者、你的收购方或你的修复提交都可以引用它。每个发现项要么对照你的源代码得到确认(确切的文件和行号、复现路径、影响分级),要么被明确定级为“仅看似成立”。没有凑数的内容,没有扫描器生成的内容,没有你无法据以行动的内容。记录还会写明我们检查了什么而没有发现问题:在这里,已记录的阴性结果是一项交付成果,而不是一次失败的委托。
每个发现项都会写明它实际达到的证据梯级:源码追踪、编译证明(按发现项的预测,使构建先失败、再通过)、测试或实际复现;对于任何概率性主张,则是一个附有区间的比率,并保留每次试验的日志;并且从不暗示更高的梯级。每一处 path:line 引用,在报告离开我们之前,都会由机器对照我们审查的确切版本加以解析。你可以核查我们的工作。这是有意为之。
我们所处的位置,是一个发现项变成一项日后需要有人为之辩护的决定的地方:裁定、关闭和签名记录;而不是扫描器争抢候选发现项的竞赛。发现问题是委托的副产品;记录才是产品。
当一个发现项经不起审视(无论是你的、你的维护者的,还是我们自己复查的审视),我们会在同一委托标识符下以书面形式撤回它,并附上理由。我们主动这样做,对方无需开口要求。撤回记录不是认错;它是一种机制。
样例:一个发现项的形态示意样例,并非来自客户委托;标识符均为占位符。报告以英文出具。
“见证者如今是免费的,校勘本却不是。”
市场已经开始比拼一个工具能生成多少发现项,但一个发现项是一位见证者,而不是一个裁决。一处 file:line 引用,是读者一分钟内就能打开并核查的东西;一个光秃秃的“Critical(严重)”则不是。在我们的记录中,严重程度是证据等级的产物,从来不是营销的素材。见证者如今是免费的,校勘本却不是。 发现项不是裁决(英文) →
四个步骤。付款之前你就知道范围,结束之后记录由你保存。
第一次委托不必涵盖你交付的全部内容。一个小而精选的范围(一个模块、一条信任边界),能以一个你可以评估的规模,产出同样站得住的记录,而且它可以成为制造商提交的第一份第二部分第 3 点证据。
流畅不是质量的标志。它恰恰是失败的方式。
当一个人写下一行代码时,会对它心存怀疑。写的人知道自己是在猜,而这种怀疑是一种安全机制,因为正是它促使人去测试这段代码。
模型写同一行代码时很流畅,用的恰恰是它写正确代码时的同一种口吻。在阅读者看来,流畅读起来就像能力。一位初级工程师交给你一份明显粗糙的东西,你会检查它。一个模型交给你两百行打磨光滑的代码,每一行都附有一个自信的理由,你就不会检查了。
陷阱不在于模型比人更常出错。而在于它们错误的答案,和正确的答案以同样的口吻出现,从外部无法区分,因为从内部也无法区分。
然后,同一个过程编写了为这段代码作证的测试,以及解释它的注释。三者彼此一致,因为三者出自同一处。这种一致读起来像三次独立的确认。其实只有一次。
“它们错误的答案,和正确的答案以同样的口吻出现。”
所以,有用的问题不是模型能否写出好代码;它能,只要有方法围绕着它。有用的问题是:当你的审查过程所检查的一切都出自同一个来源时(代码、测试、解释,以及越来越多地,你为检查它们而构建的工具),它实际在测量什么。做得好,产出是好的。做得不好,读起来一模一样。
一次审查只能找到它的审查者能找到的东西。
用一个模型检查一遍代码库,一份简短的报告告诉你的东西很窄:那个模型,用那些提示词和工具,在那一天,找出了这些。它没有找出的东西不在报告里,而且从构造上说也不可能在。
用同一个模型对同一段代码再检查一次,预计会得到另一组结果。LLM 代码审查的表现更像模糊测试,而不像静态分析器:完全相同的重跑、提示词的微小改动、新一代模型,都预计会带来不同的发现项;而且和模糊测试一样,它永远没有完成的时候。(Thomas Dullien,《实验的时代》[英文],BlueHat Asia 2026。)
这有多重要,取决于不同审查者的盲点重合到什么程度;对于代码审查,没有人测量过。关于相关性错误的研究,在包括不同供应商的模型群体中,在多项选择基准测试和一项简历筛选任务上发现了大量重合;这是否适用于发现漏洞,尚未得到确立。它确实表明的是,不同的供应商并不会自动彼此独立。
有几样东西可以给单次审查遗漏的范围划定界限:一项证明、一套测试、一个模糊测试工具、一位专家、预先植入的缺陷,或者一位与第一位不同的审查者。不能划定这一界限的,是更自信地阅读同一次审查的结果。
我们没有证明多审查者审查能发现更多真实缺陷;为检验这一点而设计的实验在开展之前即已撤销,我们公开说明了这一点。我们坚持的是一个更窄的观点: 一位审查者给出的干净结果是一个有范围的结果,把它当作代码干净的证书来读,是这个结果无法支持的推论。 完整的论证(英文) →
我们已经把详细的论证写了下来,包括我们自己方法的局限在哪里、我们尚未证明什么:一篇通俗介绍(英文),以及其背后的完整论文,已作为预印本发表, doi:10.5281/zenodo.22030516(CC BY 4.0)。它未经同行评审,论文本身也这样说明。
你可以运行同样的模型。你无法做到独立。
在你自己的代码上运行多个 AI 模型,复制了我们的工具,却失去了关键的属性。你的团队选择审查者看到什么、设定问题、评判答案,而每一个选择都把你的假设直接带回审查之中。这不是纪律上的失败;这是结构性的。一个系统的作者,不能做它自己的裁定者。
所以,即便是一次完美无瑕的内部审查,仍然是你自己关于你自己代码的说法。他们购买的,是一个愿意签名的第三方。我们不是公告机构,也不认证符合性;我们产出的是独立证据,它支持你的评估,其结构便于任何其他人重新审查。
这种方法不在乎是谁(或什么)编写了你的代码。人类编写的代码同样常常缺乏独立性。机器编写的代码只是让这个缺口变得无法忽视。
你反正也会发现。最好由我们告诉你。
CounterProof 隶属于一个开发支付和数字资产托管基础设施的集团。这套方法正是在那里锤炼出来的,这意味着,如果你在这些市场中开展业务,我们的关联方可能与你相邻,或与你竞争。
所以:在任何委托开始之前,我们会以书面形式确切地告诉你集团开发什么、在哪里运营。由你决定这是否可以接受,而且你在付给我们任何费用之前就作出决定。如果不能接受,这是一个正当的回答,我们宁愿在一开始就听到它。
我们的独立性主张确切地涵盖什么、不涵盖什么:对于由 CounterProof 或我们集团内任何公司编写的代码,我们不出具任何评估。这条界限是结构性的。它是关于我们审查谁的代码的陈述,而不是声称我们在你所在行业附近没有任何商业利益。我们的商业利益已在上文列明,由你在付给我们任何费用之前决定是否可以接受。
我们拒绝代表你作出的主张,单独列在: 我们不会主张的内容 →
三个人,具名,有据可查。
一份签名评估意味着上面有某个人的名字。下面就是这些人,以及每个名字承担什么。
我们是一家家族经营的机构(父亲、儿子和女儿),审查团队由两个人组成。这两点都是尽职调查团队自己会查到的事实,所以我们宁愿在这里说出来:一个两人的审查团队,承接的委托比一家公司少,会拒绝其领域之外的一切工作,也无法把一次薄弱的审查藏在品牌后面。这就是其中的取舍,也正因如此,这套方法被写了下来并实现了机械化,而不是只存在于某个人的脑子里。
我们在读什么,以及我们在核查什么。
如今有四种截然不同的做法都叫这个名字。它们都以攻击者的眼光看待你的代码。没有一种能单独同时给你一份来自你组织之外审查者的签名报告,以及一份清楚说明每个发现项被证明到什么程度的陈述。下文说明:我们交付什么,第二个 AI 模型不能交付什么,以及我们在你购买之前说明的局限。