该文章是OpenZeppelin对Fiamma Bridge的BitVMBridge合约进行的安全审计报告。报告总结了审计过程中发现的1个高危漏洞以及多个中低危问题,包括潜在的wrapped BTC损失、未经验证的参数、代码可读性问题等。所有发现的问题均已在后续的PR中得到解决。文章最后强调了加强链上验证、增加测试覆盖率的重要性。
TypeDeFiTimelineFrom 2025-05-14To 2025-05-16LanguagesSolidityTotal Issues19 (18 resolved)Critical Severity Issues0 (0 resolved)High Severity Issues1 (1 resolved)Medium Severity Issues2 (2 resolved)Low Severity Issues4 (4 resolved)Notes & Additional Information12 (11 resolved)
OpenZeppelin 审计了 fiamma-chain/bitvm-bridge-contracts 仓库中位于 commit 935e2cb 的 src/BitVMBridge.sol
文件。
Fiamma Bridge 是一个利用 BitVM2 框架的比特币桥,旨在实现比特币 (BTC) 与以太坊等可编程侧链之间的转移。它旨在通过为跨链资产转移提供解决方案来释放比特币在 DeFi 生态系统中的潜力。
Fiamma Bridge 促进两个主要操作:PEG-IN 和 PEG-OUT,它们分别代表将 BTC 从比特币转移到侧链,以及将代币化的 BTC 转回比特币。
将 BTC 从比特币网络成功桥接到另一个链,将执行以下步骤:
为了成功地将 wrapped BTC 提取到比特币链,将执行以下步骤:
BitVMBridge
合约上的 burn
函数,并传入他们想要将 BTC 转移到的自定义比特币地址。Burn
事件。 此事件包括发送者、比特币地址和要发送到接收者地址的值。Fiamma 桥的运营完整性取决于各种外部组件。
桥的服务器还负责使用正确的 to
接收者值调用 BitVMBridge
合约上的 mint
函数,该值由链下用户定义。 目前,to
地址可以由服务器任意设置,并且合约无法检查其正确性。
运营商负责在用户调用 BitVMBridge
合约上的 burn
函数后完成 PEG-OUT 交易,然后将 BTC 金额转移到 burn
函数参数中定义的接收者。
Fiamma 桥的激励和惩罚模型在比特币上实施。 假设这些组件已经过第三方的审计,并且运行正常。
期望 BtcTxVerifier
合约及其依赖项(如整个 btc-light-client
库)得到可靠维护并准确验证比特币交易,从而确保正确的结果。
重要的是要注意,在当前设计中,用户需要完全信任桥的服务器和运营商。 例如,当交易失败时,他们无法直接恢复其 BTC 或重放交易。
BitVMBridge
合约由部署期间定义的所有者管理。 所有者能够执行以下功能:
setParameters
:此函数允许设置以下敏感参数:
maxPegsPerMint
:调用 mint
时允许执行的最大 pegs 数量。maxBtcPerMint
和 minBtcPerMint
:铸造时允许的最大和最小 BTC 金额。maxBtcPerBurn
和 minBtcPerBurn
:燃烧时允许的最大和最小金额。mint
:执行以完成 PEG-IN 流程的函数。setMinConfirmations
:比特币上 PEG-IN 交易的最小区块确认数。setBtcTxVerifier
:验证比特币交易证明的合约。假设此合约的所有者以桥用户的最佳利益行事。
要提交 PEG-IN 交易,用户需要调用桥的链下组件以创建 PEG-IN 请求。 对于有效的请求,桥服务器将返回一个唯一的比特币地址,该地址表示使用用户的公钥和委员会的公钥生成的多重签名地址。 然后,用户构造一个 PEG-IN 交易并将金额转移到上述地址,随后,将原始 PEG-IN 交易提交到桥服务器。
桥服务器将检查构造的 PEG-IN 交易的有效性,确保金额和地址都正确,最后将 PEG-IN 交易广播到比特币区块链。 当 PEG-IN 交易被挖掘后,服务器会将其取出并调用 BitVMBridge
合约的 mint
函数,以将 wrapped BTC 铸造到用户的地址。 第 118 行 中的检查将通过确保交易有效且已被挖掘并传递最小数量的确认区块来验证比特币交易。
但是,从未检查比特币上的交易目的地。 这意味着 BitVMBridge
合约的所有者可以随时调用 mint
函数,使用来自任何通过了最小区块数的比特币交易的数据,并将其值铸造到随机地址。 这允许所有者实际上铸造过去转移的尽可能多的 wrapped BTC。
考虑实施一种机制,该机制允许验证比特币上的交易目的地是否是表示桥服务器生成的多重签名地址的正确地址。 如果所有者受到威胁,这也有助于避免灾难性损害。
更新: 已在 commit 58dcf14 的 pull request #24 中解决。 但是,由于该修复引入了一个新的 BLS 加密库,因此我们假设底层加密实现是安全的并且运行正常。 请注意,此 BLS 库未经 OpenZeppelin 审核。
在 BitVMBridge
合约中,burn
函数 用于启动 PEG-OUT 流程。 此函数是一个无需许可的函数,允许 wrapped BTC 持有者燃烧其代币。 中继器将获取此操作并在比特币链上启动交易,以将 BTC 释放到 第 138 行 中定义的 _btc_addr
。 但是,_btc_addr
参数是一个未经过验证的随机字符串。 这可能会导致潜在的用户错误,从而导致资金损失。 此外,没有恢复机制允许用户在传递无效地址时取回其丢失的资金。
考虑验证 _btc_addr
输入值以防止用户输入错误。 或者,如果此检查由链下组件执行,请考虑添加一种安全机制,以允许用户检索其资产并避免资金损失。
更新: 已在 commit 227a418 的 pull request #10 中解决。
mint
函数 用于完成 PEG-IN 流程并将 wrapped BTC 铸造到目标链上到预定义的接收者。 但是,接收者的 to
地址 未经过验证以绑定到比特币上的初始 PEG-IN 交易。 这允许恶意所有者将任何有效比特币交易的价值铸造到随机地址。
考虑实施一种机制,该机制允许验证 to
地址是否绑定到 BitVMBridge
合约的 mint
函数中的初始 PEG-IN 交易。 补充文本
更新: 已在 commit 923d3ff 的 pull request #8 中解决。 但是,由于修复是在 btc-light-client
库中实现的,因此我们假设库本身是安全的并且运行正常。 btc-light-client
库未经 OpenZeppelin 审核。
在 BitVMBridge.sol
中,发现了多个更新状态但未发出事件的函数实例:
考虑在每次发生状态更改时发出事件,特别是对于敏感配置,并确保新值实际上与当前值不同。 这将提高代码清晰度并降低错误风险。
更新: 已在 commit d35e1ea 的 pull request #5 中解决。
BitVMBridge.sol
文件当前的文档非常有限。 例如,BitVMBridge
合约、其函数、状态变量和自定义错误都缺乏全面的文档。
考虑彻底记录所有合约及其函数(及其参数),这些函数是任何合约的公共 API 的一部分。 即使不是公共的,实现敏感功能的函数也应明确记录。 相同的方法应应用于自定义错误和事件,包括其参数。 编写文档字符串时,请考虑遵循 Ethereum Natural Specification Format (NatSpec)。
更新: 已在 commit 6c52baa 的 pull request #6 中解决。
BitVMBridge
合约 继承了 OwnableUpgradeable
合约来处理其所有权逻辑。 但是,OwnableUpgradeable
以单步转移所有权。 这可能会带来风险,因为设置不正确的地址将导致永久性地失去合约的所有权,而无法恢复。
考虑继承 OpenZeppelin 的 Ownable2StepUpgradeable
合约,以利用更安全的两步所有权转移逻辑。
更新:已在 commit 923d3ff 的 pull request #7 和 commit b8ecdd7 的 pull request #27 中解决。
_disableInitializers
BitVMBridge
合约 部署在透明代理后面,以启用升级并允许代理通过调用 Initializable
中的 initialize
函数来初始化合约。 但是,该合约在其构造函数中省略了对 _disableInitializers()
的调用,这可能会允许攻击者直接初始化逻辑合约。
考虑将 _disableInitializers()
添加到 BitVMBridge.sol
的构造函数中,以防止未经授权的直接初始化逻辑合约。
更新: 已在 commit a4ab9da 的 pull request #9 中解决。
在 BitVMBridge
合约中,mint
函数 用于 PEG-IN 流程的最后一步。 此函数将基于比特币链上的有效交易将 wrapped BTC 铸造到用户的地址。 此函数接受类型为 Peg
struct 的 pegs
数组。 然后,mint
函数循环遍历 pegs
数组,并随后验证每个 peg
的输入。 但是,第 101 行 中的 value
验证是多余的,因为交易已经通过 第 118 行 中的 btcTxVerifier.verifyPayment
函数进行验证。
考虑删除 value
验证,因为它已经被另一个函数执行。 此外,考虑从 Peg
结构中删除 value
字段,以避免留下未使用的字段,从而使代码更具可读性和简洁性。
更新: 已在 commit 48f5290 的 pull request #11 中解决。
在 BitVMBridge
合约中,initialize
函数 用于将值分配给合约的状态变量。 但是,虽然某些输入参数经过验证,但 _btcTxVerifierAddr
和 _minConfirmations
未经过验证。
考虑也验证这些输入参数,以防止桥在未设置或可能错误的参数下运行。 相同的验证逻辑可以合并到 setMinConfirmations
和 setBtcTxVerifier
函数中。 随后,这些 setter 函数可以用于 initialize
函数中以配置合约的参数,确保一致地应用验证检查。
更新: 已在 commit 2e166f4 的 pull request #12 和 commit 5bc3464 的 pull request #25 中解决。
在 initialize
函数 中,_owner
参数确保与 address(0)
不同。 但是,此检查已在初始化期间的 __Ownable_init_unchained
函数 中执行。 此外,如果函数恢复,则抛出的 InvalidPegAddress
错误是不正确的错误。
考虑删除 第 53 行 中的检查以避免代码重复。
更新: 已在 commit fac96b7 的 pull request #13 中解决。
BitVMBridge.sol
文件具有 solidity ^0.8.13
浮动 pragma 指令。 Pragma 指令应固定以明确标识合约将使用其编译的 Solidity 版本。 此外,此 Solidity 版本已过时。 使用过时且未固定的 Solidity 版本可能会导致合约中的漏洞和意外行为。
考虑利用最新的 Solidity 版本来提高代码库的整体可读性和安全性。 无论使用哪个 Solidity 版本,都应考虑固定该版本以防止由于不兼容的未来版本导致的错误。
更新: 已在 commit 769b1ff 的 pull request #14 中解决。
require
语句中的自定义错误由于 Solidity 版本 0.8.26
,自定义错误支持已添加到 require
语句中。 最初,此功能仅通过 IR 管道提供,但 Solidity 0.8.27
将其支持扩展到旧版管道。
BitVMBridge.sol
包含多个可以用 require
语句替换的 if-revert
语句实例。 例如,第 54 行 可以替换为:
require(_btcPegAddr != address(0), InvalidPegAddress());
为了简洁和节省 Gas,请考虑用 require
语句替换 if-revert
语句。
更新: 已在 commit 81817b7 的 pull request #15 中解决。
在 BitVMBridge.sol
中,InvalidBtcAddress
错误 未被使用。
为了提高代码库的整体清晰度、意图性和可读性,请考虑使用或删除任何当前未使用的错误。
更新:已确认,未解决。
在 BitVMBridge.sol
中,minted
状态变量 缺少显式声明的可见性。
为了提高代码清晰度,请考虑始终显式声明状态变量的可见性,即使默认可见性与预期可见性匹配。
更新: 已在 commit 81817b7 的 pull request #17 中解决。
在代码库中使用非显式导入可能会降低清晰度,并可能导致本地定义变量和导入变量之间的命名冲突。 当同一 Solidity 文件中存在多个合约或继承链变长时,这尤其重要。
在 BitVMBridge.sol
中,当前正在使用全局导入。 遵循更清晰的代码是更好的代码的原则,请考虑采用命名导入语法 (import {A, B, C} from "X"
) 以显式声明要导入的合约、接口、结构或其他元素。
更新: 已在 commit c6a98c6 的 pull request #18 中解决。
自 Solidity 0.8.18 起,开发人员可以在映射中使用命名参数。 这意味着映射可以采用 mapping(KeyType KeyName? => ValueType ValueName?)
的形式。 此更新的语法提供了更透明的映射目的表示。
在 BitVMBridge
合约的 minted
状态变量中,映射没有任何命名参数。
考虑向上述映射中的键类型添加至少一个命名参数,以提高代码库的可读性和可维护性。
更新: 已在 commit de6f68f 的 pull request #19 中解决。
在智能合约中提供特定的安全联系人(例如电子邮件或 ENS 名称)可以大大简化个人在代码中发现漏洞时进行沟通的过程。 这种做法非常有益,因为它允许代码所有者规定漏洞披露的通信渠道,从而消除了由于缺乏如何做的知识而导致沟通不畅或未能报告的风险。 此外,如果合约包含第三方库,并且这些库中出现错误,则其维护人员可以更轻松地联系到有关该问题的合适人员并提供缓解说明。
BitVMBridge
合约 没有安全联系人。
考虑在每个合约定义上方添加包含安全联系人的 Nat### 函数可见性过于宽松
在 BitVMBridge.sol
中,发现了多个函数具有不必要的宽松可见性的实例:
BitVMBridge.sol
中的 getMinted
函数具有 public
可见性,可以限制为 external
。BitVMBridge.sol
中的 mint
函数具有 public
可见性,可以限制为 external
。BitVMBridge.sol
中的 burn
函数具有 public
可见性,可以限制为 external
。为了更好地传达函数的预期用途,并有可能实现一些额外的 gas 节省,请考虑将函数的可见性更改为仅在需要的范围内宽松。
更新:已在 pull request #21 中的 commit c76970e 中解决。
BitVMBridge
合约 的函数顺序不一致。例如,setter 函数 [1] [2] 没有遵循一致的顺序,并且出现在合约中的不同位置。
为了提高项目的整体可读性,请考虑在整个代码库中标准化排序。或者,考虑遵循 Solidity 风格指南 的建议(函数顺序)。
更新:已在 pull request #22 中的 commit 2682536 中解决。
Fiamma Bridge 是一个构建在 BitVM2 框架上的比特币到侧链协议,它实现了比特币网络和可编程侧链之间 BTC 的安全转移。我们的审计发现了一个高危漏洞,由于原始比特币交易和以太坊上的接收者之间缺乏严格的联系,该漏洞可能允许铸造无抵押的包装 BTC。此问题已通过强制执行比特币目标脚本和相应的以太坊地址之间的可验证连接来解决。
除了关键问题外,还解决了几个中低风险问题。这些问题包括对输入验证的关注、因用户错误可能造成的资产损失,以及对特权操作的限制不足。我们还提供了一些建议,以提高代码清晰度、升级安全性以及文档标准。
鉴于该桥梁对链下组件和特权角色的依赖,我们强调通过更强大的链上验证来最大限度地减少信任假设的重要性,以增强系统的弹性和可扩展性。
最后,我们发现当前的测试套件不足以确保系统的可靠性。我们强烈建议扩展测试覆盖范围,以包括常见的用法模式、边缘情况和失败场景。
Fiamma 团队在整个审计过程中都非常配合和积极响应,我们感谢他们为解决已发现问题而采取的积极措施。
- 原文链接: blog.openzeppelin.com/fi...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!