这不是 Safe core 被绕过,也不是 Squid core router 被直接攻破。 更准确地说,这是一次第三方 Safe 模块的信任边界失效:一个被 Safe 启用、被认为可信的模块,在攻击交易里变成了可编排的提款机。
SquidRouterModule相关执行路径,而不是 Safe core 本身。safe / delegate被信任,权限检查没有绑定到真实执行者和最终网关确认。expressExecuteWithToken(...) 触发模块逻辑,再由模块调用 Safe 的 execTransactionFromModule 完成 approve、Permit2approve、Universal Router swap 等高权限动作。一句话概括:Safe 正常执行了一个已启用模块的指令,真正失败的是该模块自己的授权模型。

攻击调用链
上图展示的是这次事件的核心链路:攻击者不是直接拿到 Safe owner 权限,而是通过 SquidRouterModule 的 express execution 入口,让模块代 Safe 执行资产授权和 swap。
这个差异很重要。因为在很多团队的风险模型里,Safe owner threshold 被当作最终安全边界;但一旦 Safe 启用了 module,真正的执行边界就变成了:哪些模块能调用 Safe、模块信任哪些输入、模块最终能让 Safe 做什么。
我们通过链上安全分析筛选了 Ethereum 上攻击合约和模块交互,重点观察两类成功调用:
0xf8c8f0a3expressExecuteWithToken(...),selector0xe4a974cc按成功交易聚类后,Ethereum 上可验证的攻击样式调用至少有 102 笔:

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

资金流
在链上样本中,victim Safe 流出真实资产,包括:
274.731876 USDC12,779.61993537 ENA57.427587 USDT这些真实资产进入对应池子;Safe 收到的是假币 u。
链上风险信号:这类资金流不需要等到损失完全发生后才识别。真实资产流向低可信池子、未知 token 或新建交易路径,同时 Safe 收到低可信资产,是可以在交易前模拟阶段被标红的。
技术根因:模块信任了错误的边界
问题不是某一行普通 approve写错了,而是多个信任假设叠在一起,形成了一条完整提款路径:
sourceAddress == squidRouter()被视为足够强的来源约束:来源验证没有覆盖真实调用上下文。safe 和 delegate被当作事实使用:攻击者可以围绕这些输入构造执行路径。execTransactionFromModule:一旦模块判断通过,Safe 会执行高权限操作。这就是为什么事件定性必须落在 third-party Safe module /integration path,而不是 Safe core 或 Squid core。
Safe 的模块机制没有“失灵”;它只是忠实执行了一个已启用模块提交的指令。真正出问题的是模块如何判断“谁可以让 Safe 做什么”。
很多审计会把注意力放在合约本身是否有重入、溢出、未授权 owner 操作、错误 accounting 等经典漏洞上。但这类事件的风险面更像一张执行图,而不是单个函数。
真正的问题出现在几个系统的交界处:
这些组件单独看都可能“有合理用途”。但当它们被组合起来,风险就变成了:外部输入是否能穿过跨链执行路径,最终变成 Safe 的资产操作。
对机构和协议用户来说,这也是最危险的部分。你以为自己只启用了一个路由模块,实际启用的是一条能改写资产授权和交易路径的高权限执行通道。
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 要做的,就是把这种连续验证变成默认能力。
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。
