智能合约 AI 审计实战复盘:一个 DeFi 项目的完整安全扫描流程与发现

智能合约 AI 审计实战复盘:一个 DeFi 项目的完整安全扫描流程与发现 智能合约 AI 审计实战复盘一个 DeFi 项目的完整安全扫描流程与发现一、从人工审计到 AI 辅助为何需要重构安全扫描流程传统智能合约审计依赖人工逐行审查配合 Slither、Mythril 等静态分析工具。在一个涉及借贷池、质押奖励和治理代币的 DeFi 项目中代码量超过 8000 行 Solidity跨 12 个合约文件。人工审计周期通常是 2-3 周而项目方的上线窗口只有 5 个工作日。引入 AI 辅助审计不是为了替代人工而是重构工作流的优先级。核心思路是让大语言模型完成第一轮粗筛——识别常见漏洞模式、检查业务逻辑一致性、标记潜在的访问控制缺失——再由审计工程师聚焦在高风险点和业务逻辑深度验证上。实际落地中选择了 GPT-4-turbo 结合定制化的 system prompt配合 Foundry 测试框架做自动化验证闭环。整套流程跑下来首轮即发现了 3 个中危漏洞和 7 个低危问题其中 2 个中危漏洞在人工初审阶段被遗漏了。二、AI 审计流水线架构与核心原理审计流水线分为四个阶段代码预处理、分片语义分析、漏洞模式匹配、验证回环。代码预处理阶段负责展平合约依赖、移除注释干扰、提取函数签名与状态变量。分片阶段将合约按功能模块切割——借贷逻辑、质押逻辑、治理逻辑——分别送入 LLM 的独立上下文窗口。每个分片附带一份关注清单列出该模块常见的漏洞类型。漏洞模式匹配不是简单的正则而是利用 LLM 的语义理解能力判断代码意图与实际行为的偏离。例如识别先转账后更新状态模式的时机不需要硬编码规则LLM 可以通过上下文自行判断。flowchart TD A[Solidity 源码] -- B[代码预处理: 展平签名提取] B -- C{按模块分片} C -- D1[借贷模块] C -- D2[质押模块] C -- D3[治理模块] D1 -- E1[LLM 语义分析] D2 -- E2[LLM 语义分析] D3 -- E3[LLM 语义分析] E1 -- F[漏洞报告聚合] E2 -- F E3 -- F F -- G{置信度过滤} G --|高/中置信| H[Foundry 验证脚本] G --|低置信| I[人工复核队列] H -- J{复现成功?} J --|是| K[确认漏洞] J --|否| L[误报过滤] K -- M[生成修复建议] L -- I M -- N[审计报告输出]系统 prompt 的设计是决定输出质量的关键。不能直接问这个合约有什么漏洞而是要明确指令逐函数分析状态变更顺序、检查外部调用后的状态一致性、标记所有未使用 SafeERC20 的转账操作。提示词中还嵌入了 Foundry 测试模板要求 LLM 输出可执行的 PoC 代码。三、核心实现审计引擎的代码骨架审计引擎使用 TypeScript 编写核心逻辑集中在AuditPipeline类中。以下摘取分片策略和 LLM 调用部分。// audit/pipeline.ts import { OpenAI } from openai; import { flattenSolidity } from ./flattener; import { VulnerabilityReport, AuditShard, ShardConfig } from ./types; /** * 审计流水线负责代码预处理、模块分片、LLM调用与结果聚合 * 设计决策采用分片策略而非全量送入避免上下文窗口溢出 * 同时让每个分片获得独立的分析焦点 */ export class AuditPipeline { private client: OpenAI; private maxShardSize 6000; // 每个分片最大字符数预留 prompt 空间 constructor(apiKey: string) { this.client new OpenAI({ apiKey }); } async audit(contractPaths: string[]): PromiseVulnerabilityReport[] { const allReports: VulnerabilityReport[] []; for (const path of contractPaths) { // Step 1: 展平合约处理 import 和继承 const flattened await flattenSolidity(path); // Step 2: 按函数粒度分片确保每个分片不超限 const shards this.splitIntoShards(flattened, path); // Step 3: 逐分片送入 LLM 分析 for (const shard of shards) { const shardReports await this.analyzeShard(shard); allReports.push(...shardReports); } } // Step 4: 去重与聚合 return this.deduplicateReports(allReports); } /** * 分片策略以函数为单位切分保证语义完整性 * 如果单个函数过大 maxShardSize按行继续拆分 */ private splitIntoShards(source: string, filePath: string): AuditShard[] { const shards: AuditShard[] []; // 使用正则匹配 Solidity 函数定义 const funcRegex /function\s\w\s*\([^)]*\)[\s\S]*?\{/g; const matches [...source.matchAll(funcRegex)]; if (matches.length 0) { // 无函数体如接口文件整文件作为一个分片 shards.push({ source, filePath, module: interface }); return shards; } let currentShard ; let moduleName this.inferModule(filePath); for (let i 0; i matches.length; i) { const funcStart matches[i].index!; const funcEnd i 1 matches.length ? matches[i 1].index! : source.length; const funcCode source.slice(funcStart, funcEnd); if ((currentShard funcCode).length this.maxShardSize currentShard) { shards.push({ source: currentShard, filePath, module: moduleName }); currentShard funcCode; } else { currentShard funcCode; } } if (currentShard) { shards.push({ source: currentShard, filePath, module: moduleName }); } return shards; } /** * LLM 分析单个分片 * 设计决策system prompt 中明确要求输出结构化 JSON * 降低后续解析的失败率 */ private async analyzeShard(shard: AuditShard): PromiseVulnerabilityReport[] { const systemPrompt this.buildSystemPrompt(shard.module); const response await this.client.chat.completions.create({ model: gpt-4-turbo, temperature: 0.1, // 低温度保证输出一致性 messages: [ { role: system, content: systemPrompt }, { role: user, content: 分析以下 Solidity 代码片段按 JSON 格式输出发现的安全问题\n\n${shard.source} } ], response_format: { type: json_object } }); return this.parseReports(response.choices[0].message.content, shard); } /** * 构建模块感知的 system prompt * 不同模块的漏洞关注点不同借贷关注重入和价格操纵 * 质押关注奖励计算精度治理关注提案时间锁 */ private buildSystemPrompt(module: string): string { const basePrompt 你是一名智能合约安全审计专家。分析代码时请严格按以下维度输出 1. 重入攻击风险 2. 访问控制缺失 3. 整数溢出/下溢 4. 未检查的外部调用返回值 5. 状态变量更新顺序问题 6. 闪电贷攻击向量 7. 预言机操纵风险 输出格式JSON 数组每个元素包含 severity(high/medium/low)、title、description、codeSnippet、suggestedFix。; const modulePrompts: Recordstring, string { lending: basePrompt \n特别关注借贷利率计算精度、清算机制完备性、抵押品价值计算中的价格操纵。, staking: basePrompt \n特别关注奖励计算的累计精度损失、unstaking 时间锁、复利计算是否正确。, governance: basePrompt \n特别关注提案执行延迟、投票权委托、时间锁机制是否生效。 }; return modulePrompts[module] || basePrompt; } private parseReports(raw: string | null, shard: AuditShard): VulnerabilityReport[] { if (!raw) return []; try { const parsed JSON.parse(raw); return Array.isArray(parsed) ? parsed.map((r: any) ({ ...r, filePath: shard.filePath, module: shard.module })) : []; } catch { console.warn([AuditPipeline] JSON 解析失败已跳过分片: ${shard.filePath}); return []; } } private deduplicateReports(reports: VulnerabilityReport[]): VulnerabilityReport[] { const seen new Setstring(); return reports.filter(r { const key ${r.filePath}:${r.title}; if (seen.has(key)) return false; seen.add(key); return true; }); } private inferModule(filePath: string): string { if (filePath.includes(lend) || filePath.includes(borrow)) return lending; if (filePath.includes(stak) || filePath.includes(reward)) return staking; if (filePath.includes(govern) || filePath.includes(proposal)) return governance; return general; } }验证环使用 Foundry 编写 PoC 测试。LLM 输出的漏洞报告中包含suggestedFix但更重要的是它输出了触发漏洞的条件描述。审计工程师根据描述编写 Foundry 测试在本地分叉主网验证。这个环节是人工审计与 AI 输出的交叉点——AI 负责发现人负责确认。四、边界与局限性AI 审计不能替代什么第一个边界是复杂多合约交互。当漏洞涉及 3 个以上合约的交叉调用时分片策略天然割裂了调用上下文LLM 只能看到局部状态。在实际项目中一个涉及闪电贷攻击的漏洞跨越了借贷合约、预言机合约和路由合约AI 没有识别出来最终由人工发现。第二个边界是业务逻辑深度。AI 可以判断transfer后balance是否更新但无法判断抵押率 80% 是否合理因为这个数值需要结合市场波动率、清算滑点和协议风控策略综合决策。业务逻辑的正确性验证仍然是审计中最依赖经验的部分。第三个边界是数学证明类漏洞。涉及形式化验证的漏洞如某 AMM 池的不变量是否在所有状态下成立当前的 LLM 不具备严格的数学推理能力误报率和漏报率都很高。一个值得注意的发现对同一个分片重复调用 3 次取交集可以将误报率从约 35% 降低到约 12%但漏报率会轻微上升。工程上需要在覆盖率与精确度之间做 trade-off建议用高温度参数做多次采样后再取交集作为提高准确率的手段。五、总结这次实战复盘验证了一个核心观点AI 在智能合约审计中最适合的定位是增强器而非替代者。它能显著加速初筛阶段将人工审计的精力集中到高风险、高复杂度的漏洞上。从效率数据看AI 辅助流程将首轮审计时间从预计的 14 天压缩到 5 天发现了人工遗漏的 2 个中危漏洞。但同时跨合约复杂交互漏洞和业务逻辑合理性判断仍然是 AI 的明确短板。工程化落地的关键点有三一是分片策略要与合约模块边界对齐避免割裂调用关系二是 system prompt 的领域特化程度直接决定输出质量三是必须建立验证闭环LLM 输出不做人工确认绝对不能直接作为结论。下一阶段计划引入 RAG 检索已有漏洞库让 LLM 在分析时能参考历史相似案例。