mcpField
S
solidity-audit

solidity-audit

github.com/0xlayerghost安全4157 次安装2 周前更新
代码仓库

关于 solidity-audit

面向 Solidity 合约审计与代码审查的安全检查清单 Skill,覆盖常见合约漏洞及代理、信任边界等风险。可用于按类别检查实现与安全控制。

主要功能

  1. 01检查重入与访问控制
  2. 02检查输入、预言机与数值风险
  3. 03检查签名、ERC20 与抢跑问题
  4. 04检查代理升级及跨合约信任
  5. 05检查状态顺序与地址限制绕过

适用场景

  1. 01审查 Solidity 合约的漏洞
  2. 02检查代理合约升级权限
  3. 03分析跨合约调用与状态依赖

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/0xlayerghost/solidity-agent-kit --skill solidity-audit

安装后在 Claude Code 中输入/solidity-audit确认已加载。

详细介绍

Solidity 安全审计清单

语言规则

  • 始终使用用户所用的语言回复。 如果用户用中文提问,就用中文回复。如果用户用英语提问,就用英语回复。

用法:此技能用于安全审计和代码审查。它不会自动调用——审查合约漏洞时,请调用 /solidity-audit。

合约级漏洞

1. 重入
类型说明检查项
同函数攻击者通过 fallback/receive 重新进入同一函数所有外部调用是否都发生在状态更新之后(CEI 模式)?
跨函数攻击者重新进入共享状态的其他函数所有操作共享状态的函数是否都受 nonReentrant 保护?
跨合约攻击者通过读取过时状态的其他合约重新进入外部合约是否无法读取中间状态?
只读View 函数在执行中途返回过时数据状态转换期间,是否未将关键 View 函数用作预言机?

案例:GMX v1(2025 年 7 月,4,200 万美元)——Arbitrum 上的 GLP 池发生重入,攻击者循环执行提款以耗尽流动性。

2. 访问控制
检查项详情
缺少修饰符每个修改状态的函数是否都有明确的访问控制?
修饰符逻辑修饰符是否会在检查失败时实际回滚(而不只是进行空检查)?
状态标志一次性访问模式是否会在每位用户操作后正确更新存储?
管理员权限范围所有者权限是否最小化且有时间限制?

案例:Bybit(2025 年 2 月,14 亿美元)——Safe{Wallet} UI 被注入恶意 JS,签名流程遭到劫持。这并非合约缺陷,而是基础设施层的访问控制问题。

3. 输入验证
检查项详情
零地址所有地址参数是否都拒绝 address(0)?
零金额资金转账是否拒绝零金额?
数组边界成对数组是否经过验证,确保长度相同?
任意调用是否不存在攻击者可控 data 的未验证 address.call(data)?
数值边界输入是否设定了边界,以防止尘埃攻击或 Gas 消耗攻击?
4. 闪电贷攻击
类型机制防御措施
价格操纵闪电贷借款 → 兑换以推动价格变动 → 利用依赖价格的逻辑 → 偿还设有最低流动性检查的 TWAP 预言机
治理闪电贷借入治理代币 → 投票 → 在同一区块内偿还快照投票 + 最低持有期 + ≥ 48h 的时间锁
清算闪电贷借款 → 操纵抵押品价值 → 触发清算多预言机价格验证 + 熔断器
组合(舍入)闪电贷借款 → 操纵池 → 利用舍入误差进行微量提款 → 偿还最低提款金额 + 虚拟份额

案例:

5. 预言机与价格
检查项详情
单一预言机依赖是否使用多个独立的价格来源?
价格过期是否检查 updatedAt 时间戳并拒绝旧数据?
使用现货价格是否从不使用原始 AMM 储备量进行定价?
最低流动性池储备量低于阈值时,预言机是否会回滚?
价格偏差价格相较上次已知价格变动超过阈值时,是否会触发熔断?
Chainlink 轮次完整性是否检查 answeredInRound >= roundId?

案例:Cream Finance(2021 年 10 月,$130M) — 攻击者通过减少供应量操纵 yUSD 金库价格,随后利用虚高的抵押品掏空所有借贷池。

6. 数值问题
类型描述防护措施
基本类型溢出uint256 a = uint8(b) + 1 — 在 Solidity ≥0.8 中,当 b=255 时会回滚使用一致的类型,避免隐式缩窄
截断int8(int256Value) — 即使在 ≥0.8 中也会静默溢出所有类型缩窄都使用 SafeCast 库
舍入/精度损失对较小数值,usdcAmount / 1e12 总是舍入为 0先乘后除;检查结果是否为零
先除后乘(a / b) * c 会损失精度始终使用 (a * c) / b

案例:Bunni(2025 年 9 月,$8.4M) — 微额提现中的舍入错误遭到利用,攻击者使用了闪电贷。

7. 签名问题
类型描述防护措施
ecrecover 返回 address(0)无效签名会返回 address(0),而不会回滚始终检查 recovered != address(0)
重放攻击同一签名在多个交易/链上重复使用在签名数据中包含 chainId、nonce 和 deadline
签名可塑性每个 ECDSA 签名都有两组有效的 (s, v)使用 OpenZeppelin ECDSA.recover(会强制使用 low-s)
空循环绕过在 for 循环中验证签名,攻击者发送空数组循环前检查 signatures.length >= requiredCount
缺少对 msg.sender 的绑定证明/签名未绑定到调用者始终在签名/证明数据中包含 msg.sender
8. ERC20 兼容性
问题描述防护措施
转账收费transfer(100) 实际到账的代币可能少于 100检查转账前后的余额,并使用实际收到的数量
Rebase 代币代币余额会在没有转账的情况下发生变化切勿缓存外部余额;始终读取实时余额
不返回 bool某些代币(USDT)在转账时不返回 bool使用 SafeERC20.safeTransfer
ERC777 钩子转账钩子可能触发重入所有接收代币的函数都使用 ReentrancyGuard
零金额转账transferFrom(A, B, 0) — 地址投毒拒绝零金额转账
授权竞态将授权额度从 N 改为 M 会导致可支出 N+M使用 safeIncreaseAllowance/safeDecreaseAllowance
9. MEV/抢跑
类型描述防护措施
三明治攻击攻击者在受害者交易前抢跑买入,并在其后跟跑卖出滑点保护 + 截止时间参数
ERC4626 通胀攻击首个存款人通过捐赠抬高份额价格,导致后续存款人的份额向下取整设置首笔存款最低金额,或使用虚拟份额(带偏移量的 ERC4626)
抢跑授权新授权交易确认前,攻击者先使用旧授权额度支出使用 increaseAllowance 而非 approve
无限制提现攻击者监控提现交易的内存池,并抢先发起自己的交易要求使用提交-揭示机制或绑定身份验证
10. 存储与底层
问题描述
存储指针Foo storage foo = arr[0]; foo = arr[1]; — 不会更新 arr[0]
嵌套删除delete structWithMapping — 内部 mapping 数据仍然存在
私有变量所有合约存储都可通过 eth_getStorageAt 公开读取
不安全的 delegatecall对不受信任的合约执行 delegatecall,可能导致调用方 selfdestruct
代理存储冲突升级后父合约顺序发生变化 → 变量会相互覆盖(使用存储间隙)
循环中的 msg.valuemsg.value 在循环中不会递减 — 可能导致双重花费
11. 合约检测绕过
方法工作原理
构造函数调用在构造函数中发起攻击 — 部署期间 extcodesize == 0
预计算 CREATE2 地址预先计算合约地址,在部署前将其用作 EOA
12. 代理与升级漏洞

来源:EVMbench 论文 §4.2,附录 H / Code4rena 2024-07-basin H-01

检查项详情
_authorizeUpgrade 访问控制UUPS 的 _authorizeUpgrade 必须具有 onlyOwner 修饰符吗?
无权限工厂/注册表攻击者能否使用无权限工厂(例如 Aquifer boreWell)满足升级检查?
upgradeTo 修饰符重写后的 upgradeTo/upgradeToAndCall 是否保留了 onlyProxy 修饰符?
初始化器保护initializer 修饰符能否防止重新初始化?实现合约是否调用了 _disableInitializers()?
存储布局兼容性存储布局是否支持安全升级(存储间隙或 ERC-7201 命名空间)?

案例:Code4rena 2024-07-basin H-01(引自 EVMbench 论文图 12,第 19 页)— _authorizeUpgrade 只检查了 delegatecall 和 Aquifer 注册,但缺少 onlyOwner,因此任何人都能将 Well 代理升级为恶意实现并提取资金。Oracle 补丁:添加一个 onlyOwner 修饰符。

13. 信任边界与协议可组合性

来源:EVMbench 论文 §4.2.1,图 6 / Code4rena 2024-04-noya H-08、2024-07-benddao

检查项详情
跨金库信任隔离注册表/路由器转发调用时是否验证了金库级授权?
滥用受信任发送方sendTokensToTrustedAddress 等函数是否验证来源金库,而不仅仅是路由器身份?
闪电贷与路由组合攻击者能否利用闪电贷回调让路由器冒充任意金库?
抵押品所有权验证清算/质押操作是否验证了实际 NFT/抵押品所有者?
跨合约状态依赖多合约交互是否不依赖中间状态?

案例:

14. 状态排序与计数器操纵

来源:EVMbench 论文附录 H.1,图 19-21 / Code4rena 2024-08-phi H-06

检查项详情
计数器/ID 递增顺序credIdCounter++ 或类似的 ID 递增是否发生在外部调用之前?
创建时自动购买带有自动 buy() 调用的 create() 函数是否仅在 ID/状态完全初始化后执行?
退款时机ETH 退款(超额部分)是否在所有状态更新完成后进行?
联合曲线元数据覆盖攻击者能否通过重入修改联合曲线/定价参数——先以低价买入,再切换到高价曲线,然后高价卖出?

案例:Code4rena 2024-08-phi H-06(参见 EVMbench 论文附录 H.1,第 25-28 页)——_createCredInternal 在递增 credIdCounter 之前调用了 buyShareCred;_handleTrade 在更新 lastTradeTimestamp 之前退还了超额 ETH。攻击者通过重入在低价曲线上累积份额,将元数据覆盖为高价曲线,再卖出并耗尽合约中的全部 ETH。修复方法:为 buyShareCred/sellShareCred 添加 nonReentrant。

15. 按地址状态绕过

任何基于 mapping(address => ...) 的限制,都可能通过拆分到多个地址或经由中间地址转账来绕过。

限制类型绕过方法防御措施
冷却时间(_lastTxTime[addr])A 买入 → 转给 B → B 立即卖出转账时继承发送方的冷却状态:_lastTxTime[to] = _lastTxTime[from]
单笔交易最大金额(maxTxAmount)拆分到 N 个地址,每个地址都不超限也按每个区块的 tx.origin 限制,或接受这是已知的权衡
钱包余额上限(maxWalletBalance)将代币分发到同一实体控制的多个钱包本质上很难在链上强制执行;应在链下监控
同区块保护(_lastTxBlock[addr])在同一区块中使用不同地址继承发送方的区块状态:_lastTxBlock[to] = _lastTxBlock[from]
交易次数限制轮换地址,每个地址各进行一次交易与冷却时间相同——转账时传播状态

审计方法(3 个步骤):

  1. 找出所有按地址存储的状态:搜索 mapping(address =>——对于每个映射,询问:“切换地址能否绕过此限制?”
  2. 追踪所有代币流转路径:梳理代币可能移动的所有路径(买入、卖出、转账、铸造)。检查每条路径是否都会更新限制状态。钱包到钱包的转账路径最容易被忽略。
  3. 检查状态传递性:如果 A 有限制状态并将代币转给 B,B 是否会继承该状态?如果没有,这就是可绕过的漏洞。

防御原则:限制状态应随代币流转——代币流向何处,相关的按地址状态就必须随之传递。

两个常见陷阱:

  • 通过 block.timestamp 进行骚扰攻击:使用 _lastTxTime[to] = block.timestamp 会让任何人都能通过发送少量代币来骚扰目标,重置冷却时间。应使用发送方的状态。
  • 直接赋值导致状态被覆盖:使用 _lastTxTime[to] = _lastTxTime[from] 会让冷却时间即将结束的发送方缩短接收方已有的冷却时间。应使用 max:if (_lastTxTime[from] > _lastTxTime[to]) _lastTxTime[to] = _lastTxTime[from]——只延长,不缩短。

基础设施层漏洞

16. 前端 / UI 注入

攻击者向 dApp 前端或签名界面注入恶意代码。

防御措施:签名前,确认交易 calldata 与预期的函数选择器和参数相符。使用可在设备上预览交易的硬件钱包。定期审计所有前端依赖。

案例:Bybit(2025 年 2 月,14 亿美元)——恶意 JavaScript 被注入 Safe{Wallet} UI,并在签名过程中篡改交易数据。

17. 私钥与社会工程

密钥泄露仍是 2025-2026 年损失的首要来源。

防御措施:将密钥存储在 HSM 或硬件钱包中。所有资金库和管理操作均使用多重签名(≥ 3/5)。绝不向任何“支持”人员透露助记词。定期开展社会工程意识培训。

案例:Step Finance(2026 年 1 月,3,000 万美元) — 设备遭入侵,导致资金库钱包私钥泄露。

18. 跨链桥
检查项详情
继承的代码审计从第三方框架继承的所有跨链桥逻辑
消息验证跨链消息是否通过正确的签名和重放保护进行验证?
流动性隔离跨链桥资金是否与协议资金库分离?

案例:SagaEVM(2026 年 1 月,700 万美元) — 从 Ethermint 继承了存在漏洞的 EVM 预编译跨链桥逻辑。

19. 旧版/已弃用合约

存在已知漏洞的旧合约仍可在链上被调用,且永远如此。

防御措施:永久 pause 已弃用的合约,或将资金迁出。监控旧合约地址,留意异常活动。在弃用前移除铸币/管理功能。

案例:Truebit(2026 年 1 月,2,640 万美元) — Solidity 0.6.10 合约缺少溢出保护,攻击者以近乎零成本铸造代币。

使用 Slither MCP 进行自动化分析(如可用)

配置了 slither MCP 后,请在下方的手动检查清单之前运行自动化分析:

推荐的审计流程
Step 1: slither MCP automated scan
        → get_detector_results(path, impact="High")
        → get_detector_results(path, impact="Medium")
Step 2: Review Slither findings — triage true positives vs false positives
Step 3: Manual checklist below — catch what Slither misses (business logic, economic attacks)
Step 4: Cross-reference — Slither + manual findings combined into final report
Slither MCP 工具
工具用途补充内容
get_contract_metadata提取函数、继承关系和标志手动访问控制审查
get_function_source获取带行号的精确源代码比 grep 更快地定位代码
find_implementations查找函数签名的所有实现跨合约重入分析
get_detector_results运行 90 多项安全检测器,并按影响/置信度筛选手动检查清单的自动化版本
get_detector_metadata列出可用检测器及其说明了解检查内容
Slither 擅长发现的问题与无法发现的问题
Slither 擅长发现的问题仍需手动审查的问题
重入模式业务逻辑缺陷
未受保护的函数经济攻击向量(闪电贷组合)
未使用的状态变量跨协议组合风险
遮蔽问题预言机操纵场景
不正确的 ERC20 接口信任边界架构问题
死代码特定于业务逻辑的 MEV/抢先交易问题

关键原则:Slither 通过静态分析提供真实依据,可减少对已知漏洞模式的漏报。但它无法推理协议层面的经济攻击,因此下方的手动检查清单至关重要。

平稳降级:如果未配置 slither MCP,请跳过本节,直接查看手动检查清单。所有检查项仍然有效且完整独立。

审计执行清单

进行安全审计时,请逐项检查:

重入:

  • 所有包含外部调用的函数都使用 nonReentrant
  • 遵循 CEI 模式——外部调用后不读取状态
  • 状态转换期间不使用视图函数作为预言机

访问控制:

  • 每个修改状态的函数都有明确的访问修饰符
  • 修饰符确实会回滚,而不是静默放行
  • 管理员权限最小化且有文档说明

输入与逻辑:

  • 没有未经验证的任意 call / delegatecall
  • 不使用 tx.origin 进行身份验证
  • 对成对输入验证数组长度
  • 不存在先除后乘导致的精度损失

代币处理:

  • 所有 ERC20 操作都使用 SafeERC20
  • 正确处理转账收费代币(检查余额差值)
  • 不缓存重基代币的余额
  • 拒绝零金额转账

价格与预言机:

  • 不使用原始现货价格
  • 检查价格是否过期(updatedAt / answeredInRound)
  • 强制执行最低流动性门槛
  • 设置价格偏差断路器

签名与加密:

  • 检查 ecrecover 结果是否为 address(0)
  • 签名数据包含 chainId、nonce、msg.sender、deadline
  • 使用 OZ ECDSA(强制执行 low-s)
  • 将 MerkleProof 叶节点绑定到 msg.sender

闪电贷防护:

  • 治理:快照投票 + 持有期 + 时间锁
  • 价格:使用 TWAP 或多预言机,而不是单区块现货价格
  • 金库:设置最低首次存款额或使用虚拟份额(ERC4626)

代理与升级(EVMbench):

  • UUPS _authorizeUpgrade 使用 onlyOwner — [EVMbench/basin H-01]
  • upgradeTo/upgradeToAndCall 保留 onlyProxy — [EVMbench/basin H-01]
  • 实现合约的构造函数调用 _disableInitializers() — [EVMbench/basin H-01]
  • 存储布局与升级兼容(存储间隙或 ERC-7201)— [EVMbench/basin H-01]

信任边界与可组合性(EVMbench):

  • 路由器/注册表的中继调用会验证源金库/合约授权 — [EVMbench/noya H-08]
  • 清算操作会验证抵押品的实际所有权 — [EVMbench/benddao]
  • 闪电贷回调路径无法被滥用来突破信任边界 — [EVMbench/noya H-08]
  • 多合约交互中不存在对中间状态的依赖 — [EVMbench/noya H-08]

状态排序(EVMbench):

  • 计数器/ID 递增在外部调用前完成 — [EVMbench/phi H-06]
  • ETH 退款在所有状态更新后执行 — [EVMbench/phi H-06]
  • 创建函数中的自动操作(自动买入等)在完全初始化后执行 — [EVMbench/phi H-06]

按地址绕过状态限制:

  • 审计所有针对多地址绕过的 mapping(address => ...) 限制
  • 钱包间转账路径会传递相关限制状态
  • 状态传递使用 max(_lastTxTime[to], _lastTxTime[from]),而不是 block.timestamp(可被滥用进行 griefing)或直接赋值(会覆盖并缩短限制时间)

基础设施:

  • 审计第三方依赖(桥接代码、继承合约)
  • 不存在仍可调用且带有管理员/铸造功能的弃用合约
  • 所有金库和管理员钱包均使用多签
  • 前端交易验证(calldata 与预期一致)

AI Agent 审计方法

来源:EVMbench(OpenAI/Paradigm,2026 年 2 月)——在 Detect/Patch/Exploit 模式下,针对来自 40 个 Code4rena 审计仓库的 120 个高严重性漏洞评估 AI Agent。

审计策略
  1. 覆盖优先于深度:扫描所有范围内的文件;不要在发现第一个漏洞后就停止 [EVMbench §5, p.10]
  2. 三阶段审计:检测(识别漏洞)-> 修补(编写修复方案)-> 利用(构建 PoC)[EVMbench §3.2, p.5]
  3. 增量输出:审计过程中持续记录发现,以保留进度 [EVMbench Appendix G, Fig.18, p.24]
  4. 系统性类别扫描:按漏洞类别(重入、访问控制、数值、预言机……)检查,而不是凭直觉 [EVMbench §3.1, p.4]
  5. 验证修复:修补后,确认原有测试仍能通过,且漏洞利用不再可行 [EVMbench §3.2.2, p.5]
高频漏洞模式(Code4rena 数据)

来源:EVMbench Table 4(p.17)——40 个审计仓库

  • 缺少访问控制(可升级性、清算、管理员功能)——basin H-01、munchables、benddao
  • 重入 + 状态顺序错误(在更新状态前退款)——phi H-06、noya H-08
  • 闪电贷突破信任边界(利用路由器/注册表的信任传递)——noya H-08
  • 签名重放/抢先交易(绕过检查点、重放会话签名)——sequence H-01、H-02
  • 数值精度/舍入(联合曲线、微额提款)——abracadabra H-02、size H-02
关键发现

来源:EVMbench Paper §4.1(p.7)、Fig.7(p.10)、Fig.10(p.18)、Fig.11(p.19)

  • 提供机制提示后,修补成功率从约 40% 跃升至约 94% [Fig.7]——Agent 知道如何修复,但难以发现漏洞
  • 大多数漏洞只需 ≤5 行代码即可修复 [Fig.10, p.18]
  • 大多数漏洞利用只需 1-3 笔交易 [Fig.11, p.19]
  • 发现数量最接近实际漏洞数量的 Agent 得分最高(质量 > 数量)[Fig.5, p.8]

2021-2026 年安全事件速查

日期项目损失攻击类型根本原因来源
2021 年 10 月Cream Finance$130M闪电贷 + 预言机通过减少供应量操纵 yUSD vault 价格rekt.news
2025 年 2 月Bybit$1.4BUI 注入/供应链攻击Safe{Wallet} 的 JS 因开发人员设备遭入侵而被篡改NCC Group
2025 年 3 月Abracadabra$13M逻辑缺陷cauldron 清算中的状态跟踪错误Halborn
2025 年 7 月GMX v1$42M重入Arbitrum 上 GLP 池的跨合约重入Halborn
2025 年 9 月Bunni$8.4M闪电贷 + 舍入提款舍入方向错误,导致 44 次微额提款The Block
2025 年 10 月Abracadabra #2$1.8M逻辑缺陷cook() 验证标志被重置,导致无抵押借入 MIMHalborn
2026 年 1 月Step Finance$30M密钥泄露设备遭入侵,导致金库钱包私钥被盗Halborn
2026 年 1 月Truebit$26.4M旧版合约Solidity 0.6.10 中 mint 定价的整数溢出CoinDesk
2026 年 1 月SagaEVM$7M供应链攻击/桥继承自 Ethermint 的预编译桥漏洞The Block

评论

支持 Markdown