W3

智能合约常见漏洞库

这里不是「十大漏洞排行榜」。收录标准只有一条:这个漏洞在真实链上造成过资金损失,而且根因可以用一段代码说清楚。所以每一类都写成了三段式的闭环——只讲原理的文章读完了还是不会写安全代码, 只给一段坏代码又不知道该怎么改,两段放一起才形成闭环。

漏洞条目 10严重 6高危 4中危 0静态扫描查不出 3
收录漏洞
10
每一类都配了可运行的恶意示例与修复版本
严重
6
成功利用通常意味着资金全部损失
静态扫描查不出来
3
代码语法完全正常,工具扫不出来,只能靠人推演
重入攻击
Reentrancy
严重

合约在「已经把钱转出去、但还没更新自己的账本」的那个瞬间,被转账接收方回头再调用了一次。于是同一个余额被反复支取。

重入扫描规则 3 条含攻击合约
真实案例:2016 The DAO(约 360 万 ETH)、2021 CREAM Finance(约 1.3 亿美元)
闪电贷操纵价格
Flash Loan Price Manipulation
严重

攻击者借来巨额资金,在一个交易内把某交易对的现货价格推歪,让依赖这个价格的协议做出错误判断(多放贷、错误清算、错误铸币),然后归还贷款。

预言机与价格工具查不出
真实案例:2020 bZx(约 95 万美元(两起))、2020 Harvest Finance(约 3380 万美元)
访问控制缺失
Missing / Broken Access Control
严重

特权函数忘了加权限判断,或者权限判断写错(比如用 tx.origin、只校验参数不校验调用者),任何人都能执行本该只有管理员能做的事。

权限控制扫描规则 5 条
真实案例:2017 Parity 多签钱包(约 15 万 ETH(当时约 3000 万美元))、2021 Poly Network(约 6.11 亿美元)
tx.origin 钓鱼
tx.origin Authentication
高危

用 tx.origin 判断调用者身份,攻击者就能诱骗受害者调用自己的恶意合约,由恶意合约去「冒充」受害者通过校验。因为 tx.origin 始终是最初发起交易的那个 EOA,整条调用链都骗不过它。

权限控制扫描规则 1 条
真实案例:2018 多个以太坊钱包合约(累计数百万美元级别)
可预测的随机数
Weak Randomness
严重

链上没有真正的随机数。用 block.timestamp / blockhash / msg.sender 等链上可见的值当随机源,等于把开奖结果提前公开——矿工(或任何能预测的人)都能动手脚。

随机数扫描规则 1 条
真实案例:2019 起 多款「链上彩票 / 转盘」类合约(单起数万至数十万美元)、2022 多个 NFT 盲盒铸造(稀有度被刷走)
签名重放
Signature Replay
高危

同一份签名被重复使用:跨链重放(在 A 链的签名拿到 B 链用)、跨合约重放(同一个签名被另一个合约接受)、或同链重复重放(没记 nonce,同一笔授权执行多次)。

签名与重放工具查不出
真实案例:2022 多个 Permit(EIP-2612)实现(单起数十万至数百万美元)、2022 Poly Network 等跨链桥(数亿美元级)
精度舍入与份额膨胀
Rounding / Share Inflation (First Depositor)
高危

整数除法向下取整,攻击者用「先存 1 wei,再直接转入巨额资产」把份额单价顶高,让后存入者的份额被舍入成 0 —— 他们的钱被前面的人吃掉。

算术与精度工具查不出
真实案例:2022 多个 ERC-4626 借贷金库(单起数十万至数百万美元)、2024 Sonne Finance(约 2000 万美元)
代理存储冲突与未保护升级
Proxy Storage Collision / Unprotected Upgrade
严重

代理模式下代码在实现合约、数据存在代理合约。如果实现合约的变量布局变了(加变量、调顺序、改类型),旧数据会被按新布局解读;如果升级函数没有严格的权限控制,任何人可以换成恶意实现,一次抽空全部资金。

代理与升级扫描规则 2 条
真实案例:2021 多个未保护 UUPS 代理(单起数百万美元级)、2017 Parity 库合约(约 15 万 ETH 永久冻结)
拒绝服务(DoS)
Denial of Service
高危

一个本该让所有人都能走通的操作,被某个人(或某个不可避免的状况)永久卡住:循环长度无上限、外部转账失败就整笔 revert、退款通道被恶意占位。

业务逻辑扫描规则 1 条
真实案例:2016 GovernMental(庞氏合约)(合约资金因 gas 耗尽被永久锁住)、2017 Parity 多签(第二次)(15 万 ETH 永久冻结)
蜜罐代币
Honeypot / Trap Token
严重

能买不能卖:合约里埋了只有 owner 能解的开关、黑名单、可调税率或额度上限,让普通用户买进去就出不来。这不是技术漏洞,而是故意设计的骗局。

业务逻辑扫描规则 8 条
真实案例:2021 至今 BNB Chain / 以太坊上的大量新发代币(单起数万至数百万美元,累计规模极大)、2021 Squid Game 代币(约 338 万美元)

工具查不出标记的条目,代码里没有任何可疑的写法——没有可疑的权限检查缺失,没有异常的顺序, opcode 分布也完全正常。它们靠的是运行时的状态组合(价格被操纵、签名被复用、 舍入方向被利用),历史上损失金额最大的几起事故都属于这一类。 把「静态扫描通过」当成安全结论,是这里最容易犯的错误。

每一条里都有什么

顺序是刻意排的:先讲清「为什么会出事」,再给出钱的路径,最后才给代码。 反过来先贴代码的话,读的人只会记住「重入要用 nonReentrant」, 但不知道自己在防什么。

根因

写的是「状态更新与外部调用的顺序错了」这类根因,而不是「没有加锁」这类现象。 现象层面的描述会让人把模式当成规则背下来,换个场景就失效。

攻击链

按「发生位置 → 这一笔做了什么」逐步展开,包含攻击者需要付出的成本。 免费的攻击和需要几十万美金闪电贷的攻击,防护优先级完全不一样。

有漏洞的版本

刻意写成能编译、能部署、语法完全正常的合约。漏洞不会长得像错误代码, 它就是正常的业务逻辑少了一行。

攻击者合约 / 修复版本

需要攻击合约才能成立的那些(重入、闪电贷)会额外给出攻击者那一侧的代码—— 看到回调函数长什么样,「为什么先转账会出事」就不用背了。

3 类漏洞,静态扫描一条也抓不到

它们的共同点:代码语法完全正常,危险来自「这段代码在什么环境下运行」。 工具能检查的是写法,检查不了假设。下面这几类必须靠人看懂业务:

相关:想在真实源码里找这些写法,用Rug Pull 扫描器;工具查不出的部分按审计检查清单逐项过;要亲手把 EIP-712 的字段删掉看签名怎么失效,去EIP-712 验签台;系统学一遍合约开发与部署流程,从智能合约学习路径开始。