SquidRouterModule 300 万美金被盗事件复盘:被信任的 Safe 模块,成了提款机
2026-05-2716:53
Zerodrift
2026-05-27 16:53
Zerodrift
2026-05-27 16:53
收藏文章
订阅专栏

这不是 Safe core 被绕过,也不是 Squid core router 被直接攻破。 更准确地说,这是一次第三方 Safe 模块的信任边界失效:一个被 Safe 启用、被认为可信的模块,在攻击交易里变成了可编排的提款机。

结论

  • 被攻击对象SquidRouterModule相关执行路径,而不是 Safe core 本身。
  • 损失规模:约 300 万美元级别。
  • 核心原因:模块层认证边界错位。payload 中的safe / delegate被信任,权限检查没有绑定到真实执行者和最终网关确认。
  • 攻击方式:攻击者通过expressExecuteWithToken(...) 触发模块逻辑,再由模块调用 Safe 的 execTransactionFromModule 完成 approve、Permit2approve、Universal Router swap 等高权限动作。
  • 可验证窗口:Ethereum 上攻击样式成功调用从 06:12:11UTC 开始,高密度提款集中在前三个波段,合计约 1 小时;首尾跨度超过 15 小时。
  • 关键教训:多签不是智能账户的完整安全边界。启用模块后,安全边界会扩展到模块权限、delegate、router、permit 和跨链执行路径。

一句话概括:Safe 正常执行了一个已启用模块的指令,真正失败的是该模块自己的授权模型。

攻击路径总览

攻击调用链

攻击调用链

上图展示的是这次事件的核心链路:攻击者不是直接拿到 Safe owner 权限,而是通过 SquidRouterModule 的 express execution 入口,让模块代 Safe 执行资产授权和 swap。

这个差异很重要。因为在很多团队的风险模型里,Safe owner threshold 被当作最终安全边界;但一旦 Safe 启用了 module,真正的执行边界就变成了:哪些模块能调用 Safe、模块信任哪些输入、模块最终能让 Safe 做什么。

链上证据:攻击窗口与交易形态

我们通过链上安全分析筛选了 Ethereum 上攻击合约和模块交互,重点观察两类成功调用:

  • 攻击编排合约调用:0xf8c8f0a3
  • 直接模块调用:expressExecuteWithToken(...),selector0xe4a974cc

按成功交易聚类后,Ethereum 上可验证的攻击样式调用至少有 102 笔:

  • 06:12:11 - 06:26:23 UTC:37 笔成功调用,持续约 14.2 分钟。第一波高密度调用。
  • 07:06:23 - 07:30:47 UTC:51 笔成功调用,持续约 24.4 分钟。第二波,也是最密集的提款窗口。
  • 08:27:59 - 08:49:23 UTC:5 笔成功调用,持续约 21.4 分钟。第三波,数量减少但攻击形态延续。
  • 09:18:47 UTC:1 笔后续成功调用。
  • 20:06:23 UTC:1 笔后续成功调用。
  • 21:43:11 - 21:47:11 UTC:7 笔成功调用,持续约 4 分钟。后续小簇调用。

Ethereum 攻击样式调用时间线

Ethereum 攻击样式调用时间线

从第一笔攻击样式成功调用到最后一簇成功调用,Ethereum 上的首尾跨度超过 15 小时。真正高密度提款窗口集中在前三个波段,合计约 1 小时。Base 侧需要单独链上覆盖,因此不应混入 Ethereum 的时间窗口结论。

发生了什么

Safe 模块机制本身的设计目标,是让智能账户可以自动执行复杂逻辑。Safe 允许已启用模块在自身验证通过后调用execTransactionFromModule,再由 Safe 执行交易。

这是一种强能力。它让 Safe 可以接入跨链路由、自动化执行、资金调度和策略型操作;但同样意味着,模块一旦出错,Safe 会非常可靠地执行错误指令。

这次事件中,受影响的 Safe 启用了SquidRouterModule。该模块支持 ERC20 approve、Permit2approve、Universal Router swap、wrap / unwrap 等动作,并通过PermissionsManager 为 delegate 授权。

攻击者利用的不是 Safe owner 多签路径,而是模块暴露的 expressexecution 路径。

在我们分析的 Ethereum 交易里,攻击合约调用SquidRouterModule.expressExecuteWithToken(...)。调用参数中的几个细节值得注意:

  • sourceAddress 被设置为模块配置中的 Squid Router 地址;
  • tokenSymbolWETH
  • amount0
  • payload 中携带 victim Safe、delegate 和一组 approve / swap 动作。

amount = 0 是关键风险信号。express-token 转账本身不需要真实资金成本,但 payload 仍然进入模块的高权限动作处理逻辑。换句话说,一笔看起来没有实际 token 输入成本的跨链 express 调用,最终可以驱动 Safe 做资产授权和 swap。

资金流:真实资产流出,假币流入

资金流

资金流

在链上样本中,victim Safe 流出真实资产,包括:

  • 274.731876 USDC
  • 12,779.61993537 ENA
  • 57.427587 USDT

这些真实资产进入对应池子;Safe 收到的是假币 u

链上风险信号:这类资金流不需要等到损失完全发生后才识别。真实资产流向低可信池子、未知 token 或新建交易路径,同时 Safe 收到低可信资产,是可以在交易前模拟阶段被标红的。

技术根因:模块信任了错误的边界

问题不是某一行普通 approve写错了,而是多个信任假设叠在一起,形成了一条完整提款路径:

  • express execution 可以在 gateway finalization 前触发应用逻辑:模块逻辑被提前执行。
  • sourceAddress == squidRouter()被视为足够强的来源约束:来源验证没有覆盖真实调用上下文。
  • payload 中的 safedelegate被当作事实使用:攻击者可以围绕这些输入构造执行路径。
  • 权限检查绑定 payload delegate,而不是实际 expresscaller:授权对象与真实执行者之间出现错位。
  • 模块可调用execTransactionFromModule:一旦模块判断通过,Safe 会执行高权限操作。
  • approve、Permit2、Universal Router 在一笔交易内串联:资产授权和换出可以被快速完成。

这就是为什么事件定性必须落在 third-party Safe module /integration path,而不是 Safe core 或 Squid core。

Safe 的模块机制没有“失灵”;它只是忠实执行了一个已启用模块提交的指令。真正出问题的是模块如何判断“谁可以让 Safe 做什么”。

为什么传统审计容易漏掉

很多审计会把注意力放在合约本身是否有重入、溢出、未授权 owner 操作、错误 accounting 等经典漏洞上。但这类事件的风险面更像一张执行图,而不是单个函数。

真正的问题出现在几个系统的交界处:

  • Safe module execution;
  • Axelar express execution;
  • delegate permission;
  • Permit2 approve;
  • Universal Router swap;
  • token / pool trust boundary。

这些组件单独看都可能“有合理用途”。但当它们被组合起来,风险就变成了:外部输入是否能穿过跨链执行路径,最终变成 Safe 的资产操作。

对机构和协议用户来说,这也是最危险的部分。你以为自己只启用了一个路由模块,实际启用的是一条能改写资产授权和交易路径的高权限执行通道。

ZeroDrift 可以提前做什么

ZeroDrift 要解决的不是事后写报告这个单点,而是提供持续性的 AI 链上审查、提前模拟和阻断能力,把这类模块级风险前置到攻击发生前。

1. Safe 模块风险图谱

持续扫描 Safe 的 enabled modules、guards、fallback handlers、delegatepermissions。只要某个模块具备 execTransactionFromModule能力,就纳入高危执行面,而不是只看 Safe owner threshold。

2. 权限到能力的自动推演

在模块启用、delegate 授权、router 升级或权限变更时,自动模拟外部 caller 是否能通过模块驱动 Safe 做 approve、Permit2approve、swap、bridge。重点不是函数名,而是最终能力。

3. 交易前风险预演

expressExecuteWithToken、Permit2、UniversalRouter、Safe module execution 等组合路径做 pre-execution analysis。遇到amount = 0 但后续会执行 Safe privileged actions 的路径,应直接标红或阻断。

4. 资产路径异常检测

检测真实资产是否被换入新建池、低流动性池、未知 token 或假币路径。本事件中的 u token 就是典型信号:真实 USDC /ENA / USDT 出去,低可信 token 回来。

5. 自动化阻断策略

给机构和协议用户提供 Safe module policy:拒绝未审计模块;限制 module 可调用目标;限制 Permit2 / Universal Router 额度;增加 token 和 poolallowlist;对跨链 express execution 增加 payload signature 或 gateway-finality gate。

这次事件的教训不是“不要用 Safe”,而是:智能账户安全已经从 owner 多签,变成模块权限、执行路径和资产流向的连续验证问题。

ZeroDrift 要做的,就是把这种连续验证变成默认能力。

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

专栏文章
查看更多
数据请求中

推荐专栏

数据请求中

一起「遇见」未来

DOWNLOAD FORESIGHT NEWS APP

Download QR Code