边界处的状态变化:Babylon 安全研究的经验教训

本文详细介绍了对最大的比特币质押协议 Babylon 的安全性研究,揭示了包括委托状态处理、罚没机制绕过、联合质押账目不一致以及区块提议校验中的类型断言在内的四个核心漏洞。文章还分享了通过历史漏洞模式分析和 AI 辅助挖掘漏洞的方法论,强调了在复杂状态转换和时间边界处进行安全审计的重要性。

本文介绍了我们对 Babylon 的安全研究,Babylon 是最大的 BTC 质押 DeFi 协议。我们解释了 Babylon 的工作原理、我们遇到的一类反复出现的漏洞、我们是如何发现它们的,以及我们对未来工作的思考。

免责声明:本研究于 2025 年作为一项内部倡议独立进行,不应被解释为正式的安全审计。研究结果已报告给 Babylon Labs,并得到了确认并通过了分拣。这项有时间限制的研究目标是与社区分享额外的、互补的知识。

背景

Babylon 是一个原生比特币质押协议,旨在通过共享安全架构将比特币的安全性扩展到其他网络。在这种模型中,BTC 可以被质押以帮助保护其他区块链,同时保持可恢复性并支持相对快速的解质押,并针对可证明的协议违规行为设有可配置的罚没(slashing)机制。

在撰写本文时,根据 DefiLlama 的数据,Babylon 的总锁仓价值 (TVL) 约为 $3B,使其成为最大的 BTC 质押协议。

Babylon 在安全方面进行了持续投入,包括多次第三方审计和公开安全竞赛。你可以在 Babylon 审计报告中找到审计和审查时间线。

Babylon 是如何运作的?

Babylon 是一个分层系统,协调比特币端的质押交易与一条 Cosmos SDK 链(Babylon Genesis),后者充当质押激活、投票权、终局性、检查点和奖励的控制平面。下图提供了架构概览:

arch

比特币端质押

BTC 质押使用 Taproot 输出,这些输出承诺了一个脚本树,其中包含时间锁质押、按需解质押和罚没的路径。交易有效性由 Babylon Genesis 参数和比特币确认深度控制。合规性取决于契约委员会(offchain)对某些支出的阈值签名,以及预签名的罚没交易,如果 Finality Provider 表现不当,这些交易将变得可执行。

Babylon Genesis 链

Babylon Genesis 是一条 Cosmos 链,它将协议逻辑实现为自定义的 Cosmos SDK 模块。一些关键模块包括:

  • Epoching (x/epoching):将链划分为 Epoch,并将验证者集变更延迟到 Epoch 边界。
  • Checkpointing (x/checkpointing):收集验证者签名并将它们聚合成用于比特币检查点(Checkpoint)的多重签名。
  • BTC staking (x/btcstaking):验证/激活 BTC 委托,跟踪质押参数,并维护活跃的 Finality Provider 集合和由质押衍生的投票权。
  • Finality (x/finality):验证 Finality Provider 的投票,并根据质押衍生的投票权最终确定区块。

链下组件

Babylon 还依赖链下组件在比特币和 Babylon 之间传输数据并操作质押流程。Vigilante 套件监视比特币和 Babylon,并转发关键的质押/检查点信息,以便系统能够保持其质押事件视图的更新。其他支持组件包括质押守护进程/服务、Finality Provider 软件、密钥管理和契约模拟器。

典型的质押流程

  1. 选择一个 Finality Provider 并准备一个将注册质押并接收奖励的 Babylon 账户。
  2. 从 Babylon Genesis 获取当前的 BTC 质押参数,如质押时间/价值边界和确认深度要求。
  3. 根据质押脚本格式构建所需的比特币交易和数据。
  4. 提交一个 Babylon Genesis 注册交易。在收集签名期间,该委托在 Babylon 上被跟踪为 PENDING
  5. 契约方在 Babylon 上提交其验证签名。在记录足够的签名后,委托变为已验证状态。
  6. 广播比特币质押交易并等待其获得充分确认。
  7. 链下观察者将比特币包含证明提交回 Babylon Genesis。委托变为 ACTIVE,并开始贡献投票权/赚取奖励。

研究计划

我们将研究结构化为侧重于不可信数据流的分层手动审查:

  • 层级:执行层(自定义模块)、部分共识层(ABCI++)以及链下组件。
  • 不可信输入和边界:用户提供的质押数据和交易、验证者提供的投票/提案以及跨链消息。

我们通过以下方式建立了上下文:

  • 阅读代码库,重点关注关键模块。
  • 阅读先前的审计报告,以了解以前已知的弱点。
  • 阅读 GitHub 历史:以 “fix:” 开头的 PRs,标记为 “security” 的 issues,以及安全公告,以了解它们的根本原因以及它们是如何修补的。
  • 对于已知的漏洞模式,我们检查它们是否在其他地方再次出现,或者是否可以适配到新的边缘情况中。

我们偶尔使用 AI 协助进行定位和模式搜索,但这里讨论的大多数问题都是通过 PoC 手动验证的。

研究结果

1. 委托状态处理不当导致持久的投票权

Babylon 的 x/btcstakingx/finality 模块通过 “状态更新事件” 协调投票权(例如,当委托变得有效时为 ACTIVE,当其停止贡献算力时为 EXPIRED)。问题源于 BTCDelegation.GetStatus 仅因为缺少契约法定人数就返回 PENDING,即使比特币高度已经暗示该委托即将过期。

这允许契约签名提交/验证继续进行,并最终在针对同一笔质押的早期 EXPIRED 事件之后追加一个 ACTIVE 事件。由于终局性权力更新流之后不会再看到另一个过期事件,Finality Provider 即使在 BTC 质押已过期/提取后也可以保留投票权,从而削弱了预期的终局性和共识安全假设。

GetStatus

2. Finality Provider 可以通过状态切换绕过 Jailing

Babylon 的终局性模块要求活跃的 Finality Provider (FP) 在 “终局性轮次” 中投票;活跃度规则旨在将滑动窗口(约 28 小时)内错过太多投票的 FP 进行 Jailing。在 HandleFinalityProviderLiveness 中,Jailing 条件是相对于 StartHeight 进行评估的,当 FP 变为活跃状态时,该高度会刷新。

通过在边界附近短暂离开变为不活跃,然后重新进入活跃集,FP 可以反复重置窗口,尽管长期不参与,仍可避免被 Jailing,从而削弱了预期的活跃度强制执行。

Toggling

请参阅 PoC 了解更多详情。

3. 被罚没 (Slashed) 验证者的 Co-Staking 账目错误

Babylon 的 Co-Staking 逻辑跟踪每个委托人的总额 (ActiveBaby),这会影响奖励。当一个验证者被标记为被罚没时,AfterDelegationModified Hook停止更新 ActiveBaby,并仅记录份额增量(delta-shares)。然而,BeforeDelegationRemoved Hook仍然使用罚没前的比例减去从总份额中得出的 Token 数量。

这种不一致性可能会减去在该 Epoch 中从未计入 ActiveBaby 的质押,从而降低奖励并阻碍追踪器验证。这会导致与解除委托相关的交易失败并冻结资金。

请参阅 PoC 了解更多详情。

4. 未经检查的类型断言触发验证者 Panic

在每个 Epoch 的开始,Babylon 期望一个特殊的 “注入的检查点交易” 作为区块提案中的第一个交易。在 Epoch 边界的 ProcessProposal 路径中,ExtractInjectedCheckpoint 中的解码器执行了盲目的 Go 类型断言。

恶意提案者可以在 txs[0] 中放置一个类型错误但可解码的有效单消息交易,从而在 Epoch 边界区块的验证过程中触发运行时 Panic。

请参阅 PoC修复方案 了解更多详情。

为什么这些问题容易被忽视

从这些发现中出现了两种反复出现的模式:

  • 时间边界:问题出现在特定的时间边界(Epoch 的第一个区块、活跃度滑动窗口阈值、质押过期截止点)。
  • 集中的状态变化:问题要求系统在具有特定顺序的时间窗口内观察状态转换。

在实现和审查过程中,边界条件和紧密耦合的状态转换很容易被忽视。发现它们的最好方法通常是显式地枚举状态机并测试这些边界周围的对抗性序列。

我们是如何发现它们的

除了手动审查外,我们借鉴了先前的漏洞和修复方案,然后搜索类似的模式或将它们演变为新的对抗场景。

示例 1:从修复 PR 到新的绕过方法

对于 FP Jailing 绕过,我们首先阅读了 PR #584,该 PR 修复了由 FP 切换活跃状态触发的活跃度问题。然后,我们针对窗口边界周围的其他切换边缘情况审查了终局性活跃度代码。

584

示例 2:从安全公告到类似的 Panic

对于未经检查的类型断言,我们阅读了 Nil BlockHash 公告,然后使用 AI 协助验证其他可能的攻击方法,并搜索类似的导致链停滞的故障。

示例 3:从审计发现到相关的新漏洞

我们通过阅读记录了 Vigilante 中分页漏洞的先前审计报告发现了链下问题。

vigilante_pagination_bug

检查相关逻辑发现了两个导致错过质押委托(DoS)的新问题:

  1. RPC 服务器静默地将 per_page 限制为 100,而终止逻辑将 “返回数量 < 请求数量” 视为 “完成”,导致提前退出。
  2. 单个交易可以发出多个质押事件,导致哈希数量与返回的交易数量不一致,从而导致错误的分页推进。

结论与未来工作

我们的发现强调了一个反复出现的模式:在时间边界破坏不变性的状态转换。对于未来的审计,建模状态机并在对抗性排序下验证边界行为至关重要。

虽然我们涵盖了 Babylon Genesis 链和链下组件,但比特币端的质押脚本仍然是未来研究的一个关键领域,因为它们管理着核心质押和罚没机制。

最后,虽然 AI Agent 对导航很有帮助,但它们可能难以处理多步骤、跨模块的攻击流程。未来我们可能会分享关于改进 AI 辅助漏洞猎寻的研究。

致谢

我们感谢 Babylon Labs 的专业精神。他们迅速对报告进行了分类,沟通清晰,并及时发布了修复方案。特别感谢 Jonas Merhej, Loukas Papachristoforou, Jainil Vora, 和 Ionut-Viorel Gingu 对本文的反馈。

常见问题解答 (FAQs)

什么是 Babylon,为什么 OpenZeppelin 对其进行研究? Babylon 是按 TVL 计算最大的比特币质押协议。OpenZeppelin 独立进行了这项研究,旨在为生态系统贡献安全知识。

发现了哪些类型的漏洞? 该研究确定了四个链上问题:一个允许持久投票权的委托状态缺陷、一个针对 Finality Provider 的 Jailing 绕过、一个 Co-Staking 账目不一致问题,以及一个导致验证者 Panic 的未经检查的类型断言。还发现了一个链下 RPC 逻辑问题。

这些发现背后的反复出现的模式是什么? 根本原因通常是在时间边界(如 Epoch 边界或过期截止点)破坏系统不变性的状态转换。

这些漏洞是如何被发现的? 团队使用了侧重于不可信数据流的分层手动审查,适配了已知的漏洞模式,并使用了 AI 辅助工具进行代码导航和假设验证。

局限性和后续步骤是什么? 这是一项有时间限制的研究,没有进行模糊测试(fuzzing)。未来的工作应涵盖比特币端的质押脚本,并探索改进复杂流程的 AI 辅助漏洞猎寻方法。

  • 原文链接: openzeppelin.com/news/st...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。