项目日志

跨链桥安全研究:OP Stack CrossDomainMessenger 重放漏洞

挖洞实战记录与安全技术分享

2026-06-178 分钟阅读19 Views
跨链桥安全研究:OP Stack CrossDomainMessenger 重放漏洞

跨链桥安全研究:OP Stack CrossDomainMessenger 重放漏洞

一次对 Optimism OP Stack 跨链消息机制的审计记录。

什么是 CrossDomainMessenger

OP Stack 的跨链桥基于 CrossDomainMessenger 合约,它负责在 L1(以太坊主网)和 L2(OP 链)之间传递消息。

简单来说,它的工作流程是:

  1. L1 上的合约调用 sendMessage()
  2. CrossDomainMessenger 把消息塞进队列
  3. 中继者(relayer)在目标链上调用 relayMessage()
  4. 目标合约收到消息并执行

漏洞:V0 版本缺少重放保护

我分析的是 V0(初始版本)的 relayMessage() 函数。问题出在一个关键细节——消息的 nonce 设计存在缺陷

function relayMessage(
    address _target,
    uint256 _nonce,
    bytes memory _message
) external {
    // 检查消息是否已被执行
    bytes32 messageHash = keccak256(abi.encode(_target, _nonce, _message));
    require(!executedMessages[messageHash], "already relayed");
    
    // 执行消息
    (bool success, ) = _target.call(_message);
    require(success, "relay failed");
    
    executedMessages[messageHash] = true;
}

问题分析

_nonce 参数由调用者(relayer)提供。如果在消息中包含了可变数据(比如 blockhash、timestamp),messageHash 会不同,可以重复提交不同的 _nonce 值来重放同一笔 _target.call(_message)

更关键的场景是:如果同一笔跨链消息在多个链/多个分叉上都被中继,只要 nonce 不同,消息就能被执行多次。而消息的 _target_message 数据完全一致,意味着目标合约会被调用多次——这在代币转账场景下就是双花。

影响

在 OP Stack V0 中,这个漏洞被评为 Medium。因为利用条件相对严格:

  • 需要主动构造不同的 nonce
  • 需要控制或影响中继者
  • 部分跨链桥在更高版本中已修复

但原理本身非常经典——跨链桥安全的核心问题永远是如何保证"一笔消息只被执行一次"

其他跨链桥类似问题

这不是孤例。历史上多个跨链桥都出过类似问题:

  • Wormhole — 验证器签名验证缺失(3.26 亿美元被盗)
  • Nomad — 中继者信任假设被打破(1.9 亿美元被盗)
  • Multichain — 私钥泄露导致桥资金被盗(12.6 亿美元)

我的发现思路

这个漏洞是如何找到的?说白了就是"怀疑一切"的心态:

  1. 拿到 OP Stack 合约源码
  2. 从最核心的 relayMessage() 入手
  3. 关注所有由调用者提供的参数——它们都是潜在的"攻击面"
  4. 检查状态变量的锁定逻辑——executedMessages 能否被绕过
  5. 测试 nonce 重用场景

挖合约漏洞的门槛其实不高,难的是思维方式——你得像一个攻击者那样读代码。

后续

这个发现提交到了 Cantina,被评级为 Medium,目前正在等待审核结果。

不管结果如何,这次审计让我对跨链安全有了更深的理解。跨链桥是 DeFi 里最脆弱的一环——攻击面大、责任集中、历史劣迹斑斑。如果以后继续深入安全领域,跨链一定是我重点跟的方向。

© 2026 龙的中二幻想空间 Dragon Fantasy Archive. All rights reserved.

归档标签分类ICP 备案 202400001号-1