AI 合约审计先做分诊:候选发现怎样变成可复核证据

发布时间:2026/10/24 23:59:02
AI 合约审计先做分诊:候选发现怎样变成可复核证据

同一份合约交给多个模型,通常能收回一叠措辞笃定的风险报告。问题是,其中有些路径不可达,有些依赖错误的部署配置,还有些只是重复描述同一个状态更新顺序。把报告数量当成安全进展,会把分诊工作越积越多。

以太坊基金会在 7 月发布的协议代码审计经验中,强调了真实可达性、自包含复现和独立判断的重要性。这是方法总结,不是十月新发布的模型榜单,也不能替任何模型给出本项目的准确率。方法原文

先写清楚“什么结果会推翻这条判断”

一条候选至少要包含目标版本、外部入口、预期不变量、破坏机制和复现方式。比如“提款函数可能有问题”太宽;“在余额为 2 时提交负数提款,余额不应增加”才是可以检验的主张。真实 Solidity 的无符号整数接口不会直接接受负数,这也提醒我们:针对 Python 教学模型的反例,不能冒充 EVM 漏洞。

GLM-5.3 可以作为候选生成器之一,但模型名称不能替代证据。官方编程与网络安全能力介绍描述的是产品及其评估背景,不代表下面例子实际调用过模型,更不代表模型完成了某个匿名头部协议的审计。官方研究介绍

图中提交号与命令是产物字段示意,不是本例的真实审计记录。

在一个可控目标上检查不变量

下面给出故意有缺陷的本地记账函数,以及加上前置条件的版本。目标是说明如何构造反例、如何拒绝不满足入口条件的输入,不涉及任何真实资产。

def unchecked_withdraw(balance, amount): return balance - amount def checked_withdraw(balance, amount): if not isinstance(amount, int) or isinstance(amount, bool): raise ValueError("integer amount required") if not 0 < amount <= balance: raise ValueError("amount outside allowed range") return balance - amount # Teaching counterexamples for the intentionally unchecked Python function. assert unchecked_withdraw(2, -1) > 2 assert unchecked_withdraw(2, 3) < 0 for amount in (-1, 0, 3, True): try: checked_withdraw(2, amount) except ValueError: pass else: raise AssertionError("invalid input was accepted") assert checked_withdraw(2, 2) == 0 print("2 counterexamples and 5 guarded cases checked")

保存为triage.py,运行python3 triage.py。这份程序的成功输出只证明:两个反例能破坏未检查的 Python 版本,而修正版本拒绝列出的四种非法输入并允许一次合法提款。它没有执行 Slither、Foundry 或真实合约,也没有验证合约间重入和权限模型。

工具失败不能变成“没发现问题”

审计调度器应分别记录工具退出码、输出是否可解析、测试是否真正运行,以及断言究竟检查了什么。缺少可执行文件是环境错误;JSON 无法解析是产物错误;测试编译失败是复现失败。三者都不应被一条固定的“重入漏洞”结果顶替,也不能自动算作安全通过。

候选去重可以用目标版本、入口和不变量构成键,但不要只按标题相似度合并。同一个入口可能违反不同属性;两个不同函数也可能共享同一根因。保留被拒绝的理由,比反复重新生成相同候选更有用。

真正值得交给审阅者的,是能在指定环境下重跑的证据链。模型负责扩大搜索面,工具负责给出可观察结果,人负责确认范围、影响和修复优先级。这种分工比给流水线贴上“全自动审计”标签更接近可维护的软件工程。