
Cosmos EVM 下溢漏洞从代码层面拆解 570 万美元多链攻击2026 年 8 月 20 日到 25 日Cosmos EVM 共享模块里的一个余额处理漏洞在 MANTRA、TAC、KiiChain 等六条链上被利用攻击者卷走大约 570 万美元。其中约 287 万通过去中心化交易所转移285 万通过中心化平台转移部分资金随后被冻结。这个漏洞早在 4 月 25 日就被上报当时评估认为不影响主网直到第一次攻击前大约 20 小时才把补丁 backport 到受影响的分支。这不是什么高级零日漏洞而是两个系统对同一个账户有着不同理解却没人检查它们是否一致。根因两个账本一个账户Cosmos EVM 跑在 Cosmos SDK 上面。EVM 这边的 StateDB 只记录一个数可花费余额。Cosmos SDK 的 x/bank 模块记录两个可花费余额和锁定余额比如 vesting。一个 vesting 账户可以有一部分代币是锁定的。x/staking 和 staking 预编译合约都允许把锁定的代币委托出去。委托的金额是从总额里扣不是只扣可花费的部分。问题就出在这儿。委托完成后代码会把委托后的余额写回 EVM 的 StateDB。它用 EVM 里那个更小的可花费余额去减掉全部委托金额。这个减法没有做检查。假设一个 vesting 账户有 100 可花费900 锁定然后委托 500。EVM 层执行的是 100 减 500。在 Go 的无符号整数运算里这不会报错而是回绕成大约 2²⁵⁶ 减 400。这个回绕值就是整个攻击的核心。攻击者在 EVM 状态里突然拥有了天文数字的余额。为什么对账逻辑会把漏洞变成武器Cosmos EVM 不是简单把 StateDB 的余额复制到 x/bank。它会做对账。对账时正 delta 会 mint 代币负 delta 会 burn 代币。所以攻击者有两个操作从回绕账户里转出有限金额触发在真实 Cosmos 账本上 mint用来支撑 EVM 余额。给受害者账户发送 2²⁵⁶ 减去对方实际余额的数值让对账计算出负 delta从而 burn 掉受害者的真实持仓。第二个操作才是最让人后背发凉的。攻击者不需要偷私钥不需要治理投票只需要一个无需许可的 vesting 账户以及一笔比可花费余额多委托 1 wei 的交易。这个攻击要求链上允许无需许可创建 vesting 账户很多 Cosmos EVM 链都开了这个功能。受影响的版本是 0.6.2 之前的所有版本以及 0.7.0 到 0.7.1。两条版本线的失败方式不同但同样致命。在 0.6.x 链上对账时在底层 SDK 账本上 mint 会导致供应量溢出链直接停掉。在 0.7.x 链上余额是直接写进 x/bank 的uint256 到 int256 的转换之后变化仍然保留也就是说虚增的余额会一直存在而且能花。两条路径都在一笔交易里完成净供应量变化为零发起的合约部署在一个预先算好的地址上而这个地址先被转成了 vesting 账户。代码修复减法之前先检查有漏洞的代码路径在执行委托写回时没有验证可花费余额是否足够减。修复版本 v0.6.2 和 v0.7.2 加了一个保护防止下溢。有漏洞的模式大概是这样// 有漏洞未检查的减法func(s*StateDB)ApplyDelegation(addr common.Address,amount*big.Int){current:s.GetBalance(addr)newBalance:new(big.Int).Sub(current,amount)s.SetBalance(addr,newBalance)}修复后的版本// 修复后防止下溢func(s*StateDB)ApplyDelegation(addr common.Address,amount*big.Int)error{current:s.GetBalance(addr)ifcurrent.Cmp(amount)0{returnfmt.Errorf(delegation amount exceeds spendable balance)}newBalance:new(big.Int).Sub(current,amount)s.SetBalance(addr,newBalance)returnnil}这一个检查的效果是交易直接 revert而不是产生回绕余额。没有 mint没有 burn也没有对账 delta。但光加一个检查还不够。事后报告确认修复至少涉及三个 commit包括独立锁定 vesting 余额快照以及一个模块账户防护。原因很微妙即使减法被保护了对账层仍然必须区分“EVM 余额因为正常转账而减少”和“EVM 余额因为委托动了锁定代币而减少”。后者不应该在 Cosmos 账本上触发 burn。正确的架构修复是把委托金额和喂给对账的可花费余额 delta 隔离开。委托写回应该把变化记录成 staking 操作而不是 EVM 余额变更这样对账步骤永远不会在可花费那一侧看到负 delta。代码之外出了什么问题代码 bug 本身很直接。真正把一个可修补的缺陷变成多链事件的是响应过程。Cosmos Labs 在 2026 年 4 月 25 日收到漏洞报告最初判断只影响非 18 位小数的网络并认为对生产资金没有风险。到 8 月 13 日团队确认所有 Cosmos EVM 链都受影响与小数位配置无关。修复在 5 月 15 日就已经进了主分支但 backport 版本 v0.6.2 和 v0.7.2 直到 8 月 19 日 23:01 UTC 才发布。第一次攻击在 8 月 20 日 19:06 UTC 打中 MANTRA距离补丁发布大约 20 小时。补丁说明没有点出这个漏洞。链运营方根本不知道这是一个紧急安全修复而不是普通更新。MANTRA 的事后报告指出20 小时的窗口对于组织一次破坏状态的升级来说完全不现实因为验证者集合里都是独立的网络运营方需要协调。Cosmos Labs 自己的静默补丁政策写着“当问题构成立即或全网风险时Cosmos Labs 会启动紧急缓解、私有修复分发或协调升级然后再公开披露。”团队因为早期测试认为生产链安全就把这个漏洞当成静默补丁处理。这个判断错了而且一旦 8 月 13 日确认所有链都受影响政策本身的标准就应该覆盖这个判断。这对 Cosmos 生态意味着什么这个漏洞并不新颖。它是两个模块之间的类型不匹配它们共享一个账户但对这个账户持有什么的定义不同。EVM 认为账户只有一个余额。SDK 知道账户有两个。对账层信任了 EVM 的视角却没有检查 SDK 的锁定余额是否让这个视角不完整。v0.6.2 和 v0.7.2 的修复堵住了下溢。更深层的教训是关于验证。一个if current.Cmp(amount) 0检查就能避免 570 万美元的损失。一次对受影响链运营方的私下通知就能给他们时间打补丁。还在跑 0.6.0、0.6.1、0.7.0、0.7.1 的链要么升级要么停机。补丁已经在了。攻击路径已经公开。从补丁可用到被利用的窗口已经不再以周为单位了。对于在共享基础设施上开发的开发者每一个跨模块边界的余额变更都是一个潜在的对账 bug。把检查写上。测试下溢。当安全团队说“我们在自己的配置上复现不了”的时候问一句攻击者会不会用不同的配置。