Yohaaaaan/smart-contract-audit-pipeline
GitHub: Yohaaaaan/smart-contract-audit-pipeline
一个基于不变量优先理念的多智能体 EVM 智能合约审计流水线,通过结构化推理和主网分叉验证来自动发现 DeFi 协议中的逻辑漏洞。
Stars: 0 | Forks: 0
# EVM 智能合约审计流水线





## 目录
- [问题所在](#the-problem)
- [核心理念:不变量优先](#core-thesis-invariant-first)
- [流水线](#the-pipeline)
- [目标选择:双轨模型](#target-selection-a-two-track-model)
- [反误报设计](#anti-false-positive-design)
- [盲测验证](#blind-validation)
- [工具集](#tooling)
- [构建过程中的经验教训](#what-i-learned-building-it)
- [范围与免责声明](#scope--disclaimer)
## 问题所在
DeFi 协议在不可变代码中托管着数十亿美元的用户资金。一个单一的逻辑
漏洞——缺失的访问控制修饰符、在多次操作中累积的舍入误差,或者可以在一笔交易中被操纵的预言机——都可能在几秒钟内抽干一个
协议。在攻击者之前发现这些漏洞正是智能合约审计的
核心原则。
手动审计速度缓慢,且无法扩展到每周部署的数千个新合约上。天真的自动化(仅运行静态分析器并报告其警告)会产生大量的误报,将少数真正可利用的漏洞淹没。**这条流水线旨在实现自动化的覆盖率,同时具备人类审计师的判断力**——通过在每一个阶段使推理过程变得*结构化且可验证*。
## 核心理念:不变量优先
大多数自动化工具都是**模式优先**的:它们扫描已知的错误特征
(重入签名、`tx.origin`、未检查的调用)。这能捕获教科书式的漏洞,但
会遗漏那些最重要的——特定于协议的**逻辑**漏洞,在这些漏洞中,代码
本身是正确的,但*系统*违反了其自身的某项经济规则。
这条流水线颠覆了这种方法。它首先构建协议的**模型**——
其参与者、资产和入口点——并从该模型中推导出必须始终保持成立的
**不变量**,例如:
- *“总借款额绝不能超过总抵押品价值。”*
- *“份额价格只能通过存款、取款或已实现收益来改变——绝不能通过捐赠。”*
- *“所有用户余额的总和必须等于合约的代币持有量。”*
然后,审计就变成了一个系统性的问题:**任何无权限调用序列能否破坏其中一项不变量?**只有当漏洞以一种外部攻击者(没有 owner/admin 密钥)可以触发的方式破坏了不变量时,它才算是一个真正的发现。正是这种设定让流水线能够发现模式扫描器在结构上无法察觉的*经济*和*可组合性*漏洞。
## 流水线
审计作为确定性的阶段序列运行。廉价、确定性的工作首先运行(零成本静态分析);昂贵的推理则留到它能产生价值的地方。
```
TARGET
│
▼
┌─────────────────────┐ Is this on-chain, real, in-scope code?
│ 0. PREFILTER │ Safety gate — reject empty shells & malicious clones.
└─────────────────────┘
│
▼
┌─────────────────────┐ Map the deployed system on-chain, then recover the
│ 1. SCOPE RESOLUTION │ source (verified source → decompilation fallback).
└─────────────────────┘ Resolve proxies to their live implementation.
│
▼
┌─────────────────────┐ Slither + Aderyn + Semgrep produce a normalized view:
│ 2. STATIC PRE-PASS │ call graph, storage layout, structural facts.
└─────────────────────┘ Runs in zero reasoning cost.
│
▼
┌─────────────────────┐ Build model.json: actors · assets · entry-points ·
│ 3. MODELING │ invariants. A completeness gate ensures nothing
└─────────────────────┘ funds-bearing was silently skipped.
│
▼
┌─────────────────────┐ Cluster invariants by attack surface; one specialized
│ 4. INVARIANT │ "breaker" per cluster tries to violate each invariant
│ BREAKING (swarm) │ using structural gates — not vibes.
└─────────────────────┘
│
▼
┌─────────────────────┐ Chain findings across contracts: can bug A in one
│ 5. CROSS-CONTRACT │ contract feed bug B in another? (composability)
│ CHAINING │
└─────────────────────┘
│
▼
┌─────────────────────┐ Emit VERIFIED_LEAD findings + a PoC work order for a
│ 6. VERIFIED LEAD │ separate proof-of-concept stage (Foundry on a mainnet
│ + PoC WORK ORDER │ fork) — the confirmation standard.
└─────────────────────┘
```
**设计上的多智能体。** 破坏阶段扇出展开:每个不变量集群由其自己的智能体并行处理,因此无需单个上下文一次性掌握所有内容,即可覆盖广泛的协议。最后的链接阶段会寻找单一合约视图无法捕捉到的跨合约漏洞。
**概念验证是门槛。** 一个发现不会仅仅因为听起来合理就被“确认”。流水线会为单独的阶段生成一份工作指令,利用 [Foundry](https://github.com/foundry-rs/foundry) 针对 **mainnet 状态的分叉副本**重现漏洞利用。如果漏洞无法在分叉上重现,它就不会被提交。
## 目标选择:双轨模型
在审计任何内容之前,你必须选择*审计什么*——而这正是大部分
杠杆效用所在。流水线将目标的真实目标函数建模为:
```
target_value ≈ P(a flaw exists) × P(it's monetizable) × TVL_at_risk
```
这里的洞见在于,这三种力量**朝相反的方向拉扯**,而代码的*新鲜度*则会根据你计划如何获得报酬,向*相反*的方向拉扯。
因此,系统保持了两个严格分离的轨道,它们的过滤器互不混合:
| | **轨道 A — 漏洞赏金** | **轨道 B — 独立** |
|---|---|---|
| 支付轨道 | 平台项目 (Immunefi / Sherlock / Cantina) | 直接披露 |
| 赏金基于… | 协议的**总** TVL | **可利用合约内**的 TVL |
| 因此,第一信号是… | **代码新鲜度**(成熟协议上的新漏洞是最理想的) | **实际存在的** TVL(一个全新但为空的金库毫无价值) |
一个融入模型中的研究发现:**约 75% 的漏洞在部署时就被修复了**——
时间不会*创造*漏洞。唯一真正的时间信号是**升级**:代理背后的重新部署是隐藏在蓝筹标签背后的全新、未经审查的攻击面。系统每天检测重新部署并相应地重新确定优先级,而不是将合约的年龄视为简单的过滤器。
另一个来自公开漏洞奖励计划数据的发现:**赏金翻倍,发现的关键漏洞大约会增加两倍**——这意味着巨额赏金是*专家竞争的温度计*,而不是机会的象征。旧代码上的巨额赏金挤满了数百名赏金猎人;较小、利基或刚升级的目标才是独立研究人员仍能有所发现的地方。选择逻辑将其编码为分级的最高新鲜度限制,而不是简单的“忽略任何大型目标”规则。
## 反误报设计
自动化审计最困难的部分不是寻找*候选漏洞*——而是如何不被错误的候选淹没。有几个机制纯粹是为了消灭误报而存在的:
- **锚定不变量的发现。** 只有当一个候选漏洞明确指出了它破坏的确切不变量以及破坏它的无权限路径时,它才算是一个发现。
- **结构性门控,而非直觉。** 破坏阶段根据静态预扫中的实际调用图和存储布局来检查发现,而不是凭直觉。
- **对抗性验证。** 幸存的候选漏洞面临独立的怀疑者审查,旨在*反驳*该发现;无法经受住反驳的断言将被丢弃。
- **分叉上的概念验证。** 最后一道关卡——如果无法针对真实的分叉状态重现,它就不是真实的。
其结果是刻意保守的:流水线报告**安全**的频率远高于报告漏洞的频率,因为一个错误的“严重”漏洞比错失一个线索浪费研究人员更多的时间。
## 盲测验证
声称检测率很容易;证明它才是关键。流水线在**盲测模式**下进行验证:它审计一个*已知*曾被利用的协议,但在每个阶段都对已知的漏洞进行**屏蔽**——引擎必须仅从源代码重新发现漏洞,而没有关于资金从何处流失的任何提示。
严格的防污染规则强制执行这一点:在审计封存之前,任何阶段都不得引用该事件、将其入口点偏向易受攻击的地址,或阅读任何事后分析。只有在那之后,才会揭示真实事件并对运行进行评分。
**在以这种方式审计的 10 个以前被攻击过的 DeFi 协议中,流水线在大约 60% 的案例中重新发现了根本原因漏洞**——完全盲测且仅从源代码得出。每一次遗漏都被写成事后分析,并作为与协议无关的检测网络反馈回去,以便下次能捕获同一*类别*的漏洞。
## 工具集
| 层级 | 工具 |
|-------|-------|
| **静态分析** | [Slither](https://github.com/crytic/slither), [Aderyn](https://github.com/Cyfrin/aderyn), [Semgrep](https://github.com/semgrep/semgrep) |
| **模糊测试 / 属性测试** | [Echidna](https://github.com/crytic/echidna), [Medusa](https://github.com/crytic/medusa) |
| **概念验证** | [Foundry](https://github.com/foundry-rs/foundry) (mainnet 分叉漏洞利用——确认标准) |
| **源码恢复** | Etherscan v2 / Sourcify (已验证源码) → 字节码反编译后备 |
| **链** | Ethereum, Base, Arbitrum, Optimism, Polygon (EVM) |
## 构建过程中的经验教训
一些来之不易并影响了设计的经验教训:
- **选择胜过聪明。** 决定结果的最大杠杆是*选择*审计的目标,而不是你观察得有多仔细。大部分的建模工作都投入到了目标选择逻辑中,而不是漏洞发现上。
- **新鲜度指的是升级,而不是年龄。** 一个部署了五年的合约要么是干净的,要么早就被摸透了。而一个上周刚刚*升级*过的合约则是隐藏在受信任名称背后的全新攻击面——这才是价值所在。
- **N 次运行的并集胜过一次仔细的运行。** 在冻结的模型上多次“盲测”运行破坏阶段,并提取发现的并集,能够可靠地恢复单次运行遗漏的漏洞。发现过程是嘈杂的;冗余的成本比遗漏更低。
- **一个自信的错误答案比一句保守的“安全”更糟糕。** 每一个错误的“严重”漏洞都需要花费大量时间去反驳。整个验证堆栈的存在就是为了让流水线必须经过重重考验才能获得宣布“我发现了一些东西”的资格。
## 范围与免责声明
此流水线针对 **EVM** 合约(Solidity/Vyper)。单独的轨道负责处理
Solana/Rust。所有发现均在**分叉**状态上进行验证;在没有有效披露渠道(漏洞赏金计划或直接负责任的披露)的情况下,此处的内容都不会针对线上系统使用。这是防御性安全研究。
*公开的方法论概述。引擎、目标数据和发现均为私有。*
标签:DeFi安全, EVM, 云安全监控, 多智能体, 对称加密, 智能合约审计, 自动化审计, 静态分析