引言
在 2026年9月29日和2026年10月1日 之间,攻击者利用 NEAR Intents 的入金退款处理机制,创建了没有相应资产支撑的内部余额。经核实,BNB Chain 上的 HOT Bridge 金库发生了七笔出金,转出总计 3,865,021 USDT。项目方随后发布的事后分析将该缺陷归因于 NEAR Intents 合约,并表示所有受影响资金均已于 10 月 2 日归还 [1]。
要理解这一退款缺陷如何产生可供提取的余额,需要沿着 NEAR 的异步执行流程追踪入金过程。在 NEAR 上构建应用的开发者必须考虑状态何时提交、谁能调用后续步骤,以及失败如何影响整个流程。审计也必须检查贯穿完整流程的这些交互。
基于我们审计 NEAR 合约和分析安全事件的经验,本文以此案例探讨 NEAR 上异步结算的安全性。我们首先介绍理解此次攻击所需的背景:NEAR 的异步调用与收据、代币转账与退款,以及 NEAR Intents 和 HOT Bridge 之间的关系。随后,事件分析将解释漏洞和攻击过程,再介绍修复措施与资金追回情况。最后,我们讨论状态管理和回调处理,并将讨论延伸至账户授权和存储成本。
背景
以下分析依赖三个与 NEAR 相关的背景知识:异步跨合约调用如何执行,NEP-141 和 NEP-245 如何处理代币转账与退款,以及 HOT Omni Balance 账本上的资产如何支撑 NEAR Intents 记录的内部余额。
NEAR 上的异步跨合约调用
在 Ethereum 上,合约 A 同步调用合约 B 并等待其返回结果 [2];与之不同,NEAR 会安排跨合约操作稍后执行。因此,发起调用、外部调用和回调并不共享同一个执行上下文 [3]。这一模型中有两个核心术语:
-
**Promise:**合约安排执行的操作,例如调用另一合约,或在调用之后运行回调。
-
**收据:**网络用来执行操作并在账户之间传递结果的消息。操作收据在目标账户上执行已安排的操作,数据收据则将执行结果传递给依赖该结果的操作收据 [4]。
下图以三个操作收据展示了这一调用与回调流程。在收据 A 中,合约 A 更新自身状态,并创建一个 Promise 来调用 B。收据 B 执行 B 的逻辑。图中省略的数据收据将 B 的结果传递给收据 C,由 A 的回调进行处理。收据 A 可以在 B 或回调运行之前完成执行并提交其状态。

由于这些操作收据独立执行,合约可以在等待期间处理其他请求。如果回调收据失败,该收据内所做的更改会回滚,但原始收据已提交的状态会保留。失败无法向前传播并撤销该状态,因此应用必须显式恢复一致性。
代币标准与异步退款结算
NEP-141 和 NEP-245 是 NEAR 上的代币标准。NEP-141 涵盖同质化代币,大致相当于 Ethereum 上的 ERC-20。NEP-245 涵盖多种代币类型和批量操作,大致相当于 ERC-1155 [5] [6] [7] [8]。
这种对应关系并不完全精确。普通的 NEAR 代币转账会将资产发送至目标 receiver_id,其指向的账户可能有合约代码,也可能没有。在此讨论的转账并调用流程中,接收方是一个合约账户:针对 NEP-141,它实现 ft_on_transfer();针对 NEP-245,它实现 mt_on_transfer()。接收方钩子在一个收据中执行,代币合约随后在另一个收据中运行 ft_resolve_transfer() 或 mt_resolve_transfer(),最终确定已使用的金额和退款金额。因此,始于一笔用户交易的流程可能跨越多个收据。
接收方通过其钩子报告未使用的金额。这个返回值是结算的输入,不一定是最终退款金额。在 NEP-141 的 near-contract-standards 参考实现中,解析器会同时以原始转账金额和接收方的可用余额为上限,限制报告的未使用金额。对于失败或无效的响应,系统首先将其视为请求退还全部转账金额,然后应用相同的上限 [9]。根据 NEP-245,如果 Promise 链失败,多代币解析器必须撤销代币转账 [8]。无论哪种情况,代币层面的退款都不会自动撤销接收方在更早的收据中已提交的应用状态。
NEAR Intents 与 HOT Bridge
NEAR Intents 是 NEAR 上基于意图的结算协议。用户将资产存入 intents.near,该合约将资产记为内部余额。随后,用户可以签署意图,以兑换或提取这些余额 [10]。
HOT Bridge 也称为 HOT Omni Bridge,提供跨链资产层。资产锁定在外部链的合约中,同时在 NEAR 上的 HOT Omni Balance 合约中铸造对应的全链资产。HOT Omni Balance 实现了 NEP-245 代币账本 [11]。
因此,这一集成涉及三个记账层:锁定在外部链上的资产、该资产在 HOT Omni Balance 中的全链资产表示,以及用户在 intents.near 中的内部余额。这些层必须保持一致。
下图以一笔 10 单位的入金为例,展示 Intents 记入内部余额后的两个分支。如果没有入金操作,mt_on_transfer() 返回零作为未使用金额,且不会调用接收方钩子。如果带有 DepositAction::Notify,Intents 会调用接收方,随后使用 mt_resolve_deposit(),根据接收方的响应调整记入的内部余额。在 Notify 分支中,接收方使用 6 单位,并报告 4 单位未使用。HOT Omni Balance 的 mt_resolve_transfer() 退还这 4 单位,使用户的内部余额中留下 6 单位,其 NEP-245 账本中也留下 6 单位的额外支撑资产 [12]。

事件分析
我们从三个方面分析此次事件:漏洞分析解释退款处理如何导致内部余额失去资产支撑;攻击分析追踪利用这一行为的交易和收据;修复与追回介绍已实施的更改及据报告归还资金的情况。
漏洞分析
以下源码分析基于项目方用于复现的修订版本 35044fd [13]。退款校验不足可能产生超大的退款事件,导致回调失败,使内部余额与所持资产不一致:
-
退款金额校验不足。
intents.near中受影响的入金路径以接收方的余额和请求金额为上限限制退款,却未以正在结算的这笔转账的入金金额为上限。因此,较大的既有余额可能支持远高于当前入金金额的退款。
-
**超大的退款事件。**一批包含较长代币标识符和较大退款数值的数据,可能产生序列化后超过日志大小限制的
MtBurnEvent。使用emit()发出该事件可能导致退款回调中止 [14]。这一限制适用于事件载荷,包括其中的数组和格式;仅凭较大的退款数值,不能断定事件会超出限制。
入金事件使用转账金额,因此较小的条目可使该事件保持在限制以内。后续退款事件使用解析器接受的金额。如果缺少入金金额上限,仅检查最初的事件并不能确保更大的退款事件仍符合限制。
-
**退款结算不一致。**Intents 的
mt_resolve_deposit()回调在自己的收据中扣减内部余额和供应量。如果发出退款事件导致该收据失败,这些扣减会被回滚,而较早的入金收据已提交的入账仍会保留。上游代币合约随后可能退还转入的资产,使保留下来的内部余额没有相应资产支撑。重复这一过程可能进一步扩大无资产支撑的内部余额。
Web3 领域卓越的安全审计机构
上线前验证设计、代码和业务逻辑
攻击分析
攻击者使用一种代币来填充退款事件(“填充代币”),并利用恶意接收方触发超额退款请求,反复增加没有相应资产支撑的内部余额。项目方报告称,共有 23 笔入金交易失败 [1]。经核实,七笔出金从 BNB Chain 上的 HOT Bridge 金库转出了 3,865,021 USDT。
此次攻击涉及多笔交易。本分析聚焦于 附录 A 列出的 13 笔关键交易,并按功能将其分为三个阶段。
-
阶段 1:准备(交易 1–4)。 攻击者获取了测试所需的资产,部署了恶意接收方合约,并预先为其内部填充代币余额注资。
-
阶段 2:余额放大(交易 5–6)。 交易 5 和交易 6 分别是已识别出的首笔和最后一笔余额放大交易。
-
阶段 3:在 BNB Chain 上提款(交易 7–13)。 攻击者利用被放大的内部余额,从 BNB Chain 上的 HOT Bridge 金库提取了
USDT。
这些阶段用于对攻击者的行动分类,并非三个互不重叠的时间段。余额放大与提款活动在时间上存在重叠。下文的详细还原以交易 5 及其完整的动作收据执行结果为依据,随后核查了 BNB Chain 上的七笔提款。
第一个余额放大示例使用了此处列出的恶意接收方;后续交易使用了其他恶意接收方账户。完整地址和代币 ID 见附录 B。以下时间均为 UTC。
| 下文使用的名称 | 角色 | 链 |
|---|---|---|
| 攻击者 | 由攻击者控制的交易发送方 | NEAR |
| 恶意接收方 | 通知回调合约/内部余额所有者 | NEAR |
| 填充代币 | 攻击者提供的批次填充代币 | NEAR |
USDT 映射代币 |
在 NEAR 上表示的 BNB Chain 资产 | NEAR |
USDT |
底层代币 | BNB Chain |
| Intents | 内部结算合约 | NEAR |
| HOT Omni Balance | NEP-245 代币账本 | NEAR |
| BNB 接收方 | 由攻击者控制的提款接收方 | BNB Chain |
| HOT Bridge 金库 | 跨链资产金库 | BNB Chain |
阶段 1:准备(交易 1–4)
-
步骤 1(交易 1):9月29日 12:30:44,攻击者通过 HOT Bridge 获取了
10e18个原始单位的 BNB ChainUSDT映射代币,并将其记入攻击者在 HOT Omni Balance 中的账户。代币 ID 的后缀解码后,对应附录 B中的 BNB ChainUSDT地址。按 18 位小数计算,10e18个原始单位相当于 10USDT。 -
步骤 2(交易 2):攻击者通过 HOT Bridge 获取了
97e36 + 97个原始单位的填充代币。该定制代币于当天早些时候在 Osmosis 上创建并铸造,随后经 Kava 和 Gonka 转移,最终在 NEAR 上被领取;准备阶段的记录详见附录 C。 -
步骤 3(交易 3):攻击者部署并初始化了恶意接收方合约。
-
步骤 4(交易 4):攻击者通过 HOT Omni Balance 的
mt_transfer_call(),将97e36个原始单位的填充代币转给了 Intents,其中msg指定恶意接收方。Intents 将代币记入恶意接收方的内部账户。这笔预先注入的余额使恶意接收方能够在交易 5 中支持 97 个退款请求,每个请求的金额为1e36个原始单位。
阶段 2:余额放大(交易 5–6)
首笔余额放大交易,即交易 5,于9月29日 16:14:19 执行。其五个核心动作收据涵盖批量转账、存入、通知、失败的账务调整以及上游退款。收据标识符和执行结果见附录 D。
-
步骤 5(交易 5):攻击者调用了 HOT Omni Balance 上的
mt_batch_transfer_call(),以 Intents 为目标。该批次包含同一种填充代币的 97 个条目,每个条目的金额为 1 个原始单位,另有一个金额为10e18个原始单位的USDT条目。Intents 的mt_on_transfer()将全部 98 个条目记入恶意接收方名下,并发出了MtMint存入事件。将每个填充条目的金额设为 1 是刻意安排的:存入流程调用check_refund(),验证初始事件及其预期退款开销是否处于日志大小限制之内。较小的存入金额通过了这项检查,而恶意接收方随后提出的大额退款请求产生了超出大小限制的退款事件 [13]。
-
步骤 6(交易 5):完成内部余额记账后,Intents 进入
DepositAction::Notify分支,并将全部 98 个条目一次性传给恶意接收方的mt_on_transfer()。恶意接收方调用成功,针对填充代币条目返回了 97 个退款请求,每个请求的金额为1e36个原始单位;针对USDT条目则返回了一个金额为 0 的退款请求。 -
步骤 7(交易 5):由于在交易 4 中预先注入的恶意接收方内部填充代币余额足以支付退款,Intents 的
mt_resolve_deposit()接受了全部 97 个退款请求,每个请求的金额为1e36个原始单位。这些大额退款数值,加上重复出现的长代币标识符,使MtBurnEvent日志膨胀至 16,495 字节,超过了 16,384 字节的限制。发出事件失败,导致该收据尝试进行的余额扣减被回滚,但此前记入的存入余额仍然保留。
-
步骤 8(交易 5):HOT Omni Balance 的
mt_resolve_transfer()收到了来自 Intents 的mt_resolve_deposit()的失败 Promise 结果。因此,它按最初转入的金额将全部 98 个条目退还给攻击者,其中包括 10USDT,尽管恶意接收方请求退还的USDT金额为零。攻击者收回了资产,而恶意接收方在 Intents 中保留了对应的内部余额。
攻击者重复这一流程,进一步放大内部余额。交易 6使用了另一个恶意接收方,并触发了相同的日志长度超限失败。
阶段 3:在 BNB Chain 上提款(交易 7–13)
- 步骤 9(交易 7–13):攻击者利用被放大的内部余额,通过 HOT Bridge 请求提款。在 BNB Chain 上,附录 A 中列为交易 7–13 的七笔交易将
USDT从 HOT Bridge 金库转给了由攻击者控制的 BNB 接收方。
前两笔小额提款合计 21 USDT。随后五笔合计 3,865,000 USDT,因此七笔交易总计为 3,865,021 USDT。这些金额依据该代币的转账日志及其 18 位小数精度得出。BNB Chain 上的时间戳记录的是目标链上的转账,应与 NEAR 上的存入或提款请求时间戳区分开来。
修复与资金追回
团队报告称,修复方案已于10月2日部署 [1]。修正后的退款计算将每笔退款限制在当前转账的存入金额以内,同时保留请求金额和可用内部余额施加的限制 [15]:
let refund_amount = requested_refund.min(*deposited).min(balance_left);
这可防止此前存入所形成的大额余额被用于支持后来一笔较小存入的超额退款。
随后,团队于10月7日移除了存入通知 [1],关闭了恶意接收方提供退款请求的路径。PR #374 记录了这一移除操作 [16]。事后分析报告还提到一项额外保障措施:监控机制现会比较用户内部余额总额与合约实际持有的代币数量,并在两者不一致时自动暂停合约 [1]。
关于资金追回,项目方于10月2日宣布,所有资金均已归还 [17]。其后发布的事后分析报告确认,所有受影响用户的损失均已得到弥补 [1]。
NEAR 智能合约的安全注意事项
这一事件为审视 NEAR 异步收据之间的状态一致性提供了切入点。基于上述分析和我们的 NEAR 审计经验,本节讨论三个方面:异步执行、通过访问密钥进行账户授权,以及存储成本。后两个方面将讨论延伸至应用如何委托权限并为持久化状态支付费用。重点是受这些 NEAR 机制影响的风险,以及开发和审计期间需要开展的具体检查;在有助于解释或应对这些风险时,也会纳入通用安全实践。

异步执行
1.跨收据的状态管理
在 NEAR 上,跨合约调用及其回调在不同的收据中执行,后续失败不会自动撤销此前已提交的状态。合约还可以在调用待完成期间处理其他请求,因此,状态更新的时机和隔离对于保持内部余额与实际资产一致至关重要。以下三种常见情形说明了这些风险:
-
延迟扣减余额: 如果直到回调时才扣减或预留可用余额,那么同一笔资金可能在转账结算前再次被使用。
-
过早记入存入余额: 在外部处理完成前将资金记入可用余额,会产生两种风险:
- 结算前使用资金: 用户可能在外部调用仍待完成、结算尚未最终完成时,使用已记入的资金。
- 回调失败后余额仍被保留: 如果退款回调失败,上游代币合约可能退还资产,而此前已提交的内部余额仍被保留。NEAR Intents 事件体现了这一风险。
-
共享状态被覆盖: 如果待处理的请求共用一个存储用户或金额的变量,后续请求可能覆盖较早请求的回调所需的信息。退款随后可能被关联到错误的用户或金额。
**建议。**由于 NEAR 上的跨合约流程在不同收据之间并非原子执行,开发和审计时都需要考虑余额更新的时机、待处理请求的隔离,以及调用和回调失败后的恢复。在发起出金前扣除或预留资金;如果转账失败,只恢复一次余额。对于入金,应防止用户在结算最终完成前使用资金,并确保退还的资产不会留下可使用的内部额度,包括结算回调本身失败的情况。为每个待处理请求分别记录用户、金额和结算状态。针对成功与失败的调用、回调失败、交错执行的请求以及重复结算尝试,验证上述行为。
2. 跨合约调用中的回调
NEAR 合约使用 Promise 调度跨合约调用,并通过回调处理调用结果。回调的访问控制和失败处理决定后续记账或结算能否按预期运行。由此产生两类风险:
-
**不受限制的回调访问:**回调必须作为可调用的合约方法对外暴露,但除非限制访问,否则外部调用者也能调用它。攻击者可能使用伪造的参数调用未受保护的回调,使记账或结算逻辑在预期的前置操作尚未发生时运行。
-
**回调失败:**NEAR 合约使用
.then()附加回调,以处理跨合约调用结果并执行所需的收尾或恢复逻辑。如果回调本身失败,其自身的状态变更会被回滚,但此前已成功执行的收据仍保持已提交状态,导致状态结算不一致。
**建议。**使用 #[private] 将回调的调用权限限制为合约自身 [18]。为回调分配充足的 gas,并限制其可能执行的工作量和产生日志的数量。明确处理失败的 Promise 结果和格式错误的返回数据。由于失败的回调无法提交自身的恢复变更,应在更早的收据中记录恢复所需的待结算状态。验证回调失败后不会留下缺乏资产支持且可使用的额度,并确保恢复过程不会对同一操作结算两次。
账户授权
NEAR 通过两种访问密钥提供细粒度的账户授权 [19]:Function-Call 密钥和 Full Access 密钥。
如果用户使用 Function-Call 密钥授权某个网站,该网站便可在每次操作时无需获取新的钱包签名,就对获准的接收方调用获准的方法。运行时会强制执行这一权限范围,并拒绝使用此类密钥发起的附带非零押金的调用 [20]。
在这一权限范围内,仅凭账户身份,无法区分某项操作是使用委托密钥签署的,还是由用户逐项批准的。如果授权范围包含转账、出金或权限变更方法,那么仅依赖账户身份的敏感方法可能允许恶意网站发起这些操作。
**建议。**审查可通过受限密钥调用的敏感方法,以及每项操作所需的授权。通过 #[payable] 和 assert_one_yocto() 要求附带恰好 1 yoctoNEAR,可排除受限密钥直接发起交易的路径。仍须保留应用自身的身份与权限检查:附带押金的要求并不能证明操作由人发起,因为软件可以持有 Full Access 密钥,而另一个合约也可以附带 NEAR。
存储成本
NEAR 要求合约为其存储的数据预留 NEAR,因此状态增长会减少可用于其他操作的资金 [21]。风险取决于由谁承担增长带来的成本:
-
**协议出资的存储:**如果用户无需付费即可创建记录,且增长不受限制,反复进行低成本调用就可能增加合约的存储资金占用,并耗尽其可用资金。
-
**用户出资的存储:**向用户收费既要求费用足额覆盖成本,也要求准确计量:
- **绕过收费:**其他入口可能在不收取常规注册或写入路径所要求费用的情况下创建记录。
- 用量归属错误:
env::storage_usage()衡量的是整个合约的存储用量。在外部调用前保存基准值,再于之后的收据中进行比较,可能将无关的写入或删除纳入计算,导致收费高于或低于该用户自身存储用量的变化。
**建议。**需要统筹考虑存储费用来源、写入路径的收费覆盖情况和用量归属。对新增存储收费,或明确限制协议补贴及容量。检查每条写入路径是否能绕过收费。尽可能在同一收据内计量某项操作造成的存储变化;当记账跨越多个收据时,应先剔除无关变化,再将用量归属到单个用户。
结论
在 NEAR 上,即使后续回调失败,已成功执行的收据仍可能留下持久的状态。与以太坊上的同步调用链不同,跨收据流程没有共同的回滚边界。因此,应用必须考虑每种可能的失败发生后仍然保留的状态和资产。
在 NEAR Intents 事件中,代币退款已完成,但相应的内部额度在记账调整失败后仍然保留。退款验证不足,使退款数额大到足以触发该失败。这一案例表明,即使资产已在代币层退还,应用中仍可能留下缺乏资产支持、可供使用的余额。
对于类似的异步流程,开发和审计应追踪每种可能的失败发生后哪些状态变更仍然保留、待结算余额能否被使用,以及如何在不重复入账或退款的情况下恢复未完成的结算。检查每份收据时,必须结合其所依赖的先前状态和它所调度的后续操作。
除结算外,还应明确审查访问密钥权限和存储费用来源:委托调用必须保持在预期的授权范围内,而由用户推动的状态增长必须有明确的费用承担方或上限。
参考资料
[1] NEAR Intents 事后分析,2026年10月16日
[3] NEAR 文档:跨合约调用
[5] ERC-20:代币标准
[6] ERC-1155:多代币标准
[7] NEP-141:同质化代币标准
[8] NEP-245:多代币标准
[9] NEAR SDK 同质化代币实现
[11] HOT Bridge 架构与 HOT Omni Balance
[12] NEP-245 入金流程,复现版本 35044fd
[13] 入金解析器,复现版本 35044fd
[15] 当前 Intents 源码中的退款金额限制,访问于 2026年10月26日
[16] PR #374:移除入金通知
[17] NEAR Intents 资金追回声明,2026年10月2日
[18] NEAR 文档:私有回调
[19] NEAR 文档:访问密钥
[20] NEAR RuntimeSpec:函数调用访问密钥验证
[21] NEAR 文档:存储成本攻击
附录
A. 交易时间线 {#appendix-verified-transaction-timeline}
本附录沿用原始调查中的交易编号,列出四笔准备阶段交易、已识别的首笔和末笔余额放大交易,以及七笔 BNB Chain 出金交易。这并非项目报告的全部 23 笔失败入金交易的完整清单。所有时间均为 UTC;阶段按操作分类,时间上可能重叠。
| 交易 | 阶段 | 链 | 时间 (UTC) | 操作 | 交易 |
|---|---|---|---|---|---|
| 1 | 准备 | NEAR | 2026-09-29 12:30:44 | 获取 10 USDT 的映射代币 |
9SiSBvDe... |
| 2 | 准备 | NEAR | 2026-09-29 16:09:34 | 获取填充代币 | FmwaoRND... |
| 3 | 准备 | NEAR | 2026-09-29 16:11:48 | 部署并初始化恶意接收方 | GgbwMV8N... |
| 4 | 准备 | NEAR | 2026-09-29 16:12:40 | 预先充入恶意接收方的内部填充代币余额 | 4wf2FWcE... |
| 5 | 余额放大 | NEAR | 2026-09-29 16:14:19 | 已识别的首笔余额放大交易 | 3k91uDpU... |
| 6 | 余额放大 | NEAR | 2026-10-01 05:47:27 | 已识别的末笔余额放大交易 | GAQKwHdT... |
| 7 | 跨链出金 | BNB Chain | 2026-09-30 18:57:07 | 从 HOT Bridge 金库向 BNB 接收方转出 10 USDT |
0x4f426e23... |
| 8 | 跨链出金 | BNB Chain | 2026-09-30 20:05:24 | 从 HOT Bridge 金库向 BNB 接收方转出 11 USDT |
0xc002bd17... |
| 9 | 跨链出金 | BNB Chain | 2026-09-30 23:54:30 | 从 HOT Bridge 金库向 BNB 接收方转出 800,000 USDT |
0x9fe58e03... |
| 10 | 跨链出金 | BNB Chain | 2026-10-01 00:24:02 | 从 HOT Bridge 金库向 BNB 接收方转出 1,200,000 USDT |
0x0381265d... |
| 11 | 跨链出金 | BNB Chain | 2026-10-01 00:50:42 | 从 HOT Bridge 金库向 BNB 接收方转出 1,500,000 USDT |
0x69d1c68c... |
| 12 | 跨链出金 | BNB Chain | 2026-10-01 01:46:20 | 从 HOT Bridge 金库向 BNB 接收方转出 330,000 USDT |
0x9c10b967... |
| 13 | 跨链出金 | BNB Chain | 2026-10-01 06:08:26 | 从 HOT Bridge 金库向 BNB 接收方转出 35,000 USDT |
0x16ddfa69... |
B. 账户与代币标识符 {#appendix-accounts-and-token-identifiers}
原始调查将下列两个跨链地址均归属于攻击者。链上记录独立证实了它们分别作为 NEAR 交易发送方和 BNB Chain 出金接收方的角色。此处列出的恶意接收方是 Tx 5 中使用的账户;后续用于扩大攻击规模的交易使用了其他恶意接收方账户。
| 下文使用的名称 | 角色 | 链 | 账户 / 标识符 |
|---|---|---|---|
| 攻击者 | 由攻击者控制的交易发送方 | NEAR | 20e6bfe4685d99004fc2095d3a0fc6158cd810ce8f801196141e183ed6e19d65 |
| 恶意接收方 | 通知回调合约 / 内部余额所有者 | NEAR | dd1fe58ec316ada5b673b88c14fe2fa2b7ede82080440901dfbd64b994241757 |
| 填充代币 | 攻击者提供的批次填充代币 | NEAR | 4444119_ |
USDT 的映射资产 |
在 NEAR 上表示的 BNB Chain 资产 | NEAR | 56_2CMMyVTGZkeyNZTSvS5sarzfir6g |
USDT |
底层代币 | BNB Chain | 0x55d398326f99059ff775485246999027b3197955 |
| Intents | 内部结算合约 | NEAR | intents.near |
| HOT Omni Balance | NEP-245 代币账本 | NEAR | v2_1.omni.hot.tg |
| BNB 接收方 | 由攻击者控制的出金接收方 | BNB Chain | 0x09Fd1f5d9F185067A92493E43AA259ea4AB3ad37 |
| HOT Bridge 金库 | 跨链资产金库 | BNB Chain | 0x233c5370CCfb3cD7409d9A3fb98ab94dE94Cb4Cd |
C. 填充代币的创建与跨链桥转账 {#appendix-filler-token-origin}
填充代币最初是通过 Osmosis TokenFactory 创建的自定义资产。其创建、铸造及后续转账将它与攻击准备工作联系起来。下列时间均为 2026年9月29日 的 UTC 时间;NEAR 上的领取对应附录 A 中的 Tx 2。
| 时间 (UTC) | 链 | 操作 | 交易 |
|---|---|---|---|
| 14:00:29 | Osmosis | 创建代币面额 | C489A91E... |
| 14:01:03 | Osmosis | 铸造 97e36 + 97 个原始单位 |
5FD2CF0E... |
| 14:02:00 | Osmosis | 通过 IBC 将铸造所得数量转至 Kava | 8EFD2659... |
| 14:02:32 | Kava | 通过 IBC 将相同数量转至 Gonka | D26EABBE... |
| 14:16:07 | Gonka | 将该资产存入 HOT Bridge | 41982DF3... |
| 16:09:34 | NEAR | 在 HOT Omni Balance 中领取其映射资产(Tx 2) | FmwaoRND... |
同一个 Osmosis 账户创建、铸造并发送了该代币。两笔 IBC 转账均携带备注 hot intents ctf filler。铸造数量为 97e36 + 97 个原始单位,与两笔转账、Gonka 上的跨链桥存入以及 NEAR 上的领取数量一致。Osmosis 转账的接收方是 Kava 转账的发送方,而 Kava 转账的接收方又是 Gonka 跨链桥存入交易的发送方。这些记录共同表明,该代币是作为攻击准备工作的一部分而创建的。
Gonka 面额溯源记录记载了 IBC 路径 transfer/channel-5/transfer/channel-1 和原始 Osmosis 资产标识符:
| 资产层级 | 标识符 |
|---|---|
| 原始 Osmosis 面额 | factory/osmo1dnjr753vam6 |
| Gonka IBC 面额 | ibc/C679139C206D0E7379C1 |
对 NEAR Tx 2 中的 contract_id 进行 Base58 解码,会得到上表中的 Gonka IBC 面额。Gonka 跨链桥存入交易与 NEAR 上的领取交易使用相同的 nonce 1790691367000000007133;源存入交易中的接收方哈希也与攻击者 NEAR 账户 ID 的 SHA-256 哈希一致。这些字段将源存入交易与 NEAR 上的余额记入关联起来。“填充代币”这一名称描述了该资产在扩大退款事件规模方面的作用。
D. Tx 5 的收据详情 {#appendix-tx5-receipts}
下列五份核心操作收据对应步骤 5–8。步骤 5 同时包含最初的 HOT Omni Balance 转账和 Intents 存入收据。
| 对应步骤 | 收据 | 执行方 | 方法 | 结果 |
|---|---|---|---|---|
| 5 | 8fWiEwQUbVATPC3J |
HOT Omni Balancev2_1.omni.hot.tg |
mt_batch_transfer_call() |
成功;转移了整批资产,并安排执行 Intents 的 mt_on_transfer() |
| 5 | DSfNwH18mEASbDg2 |
Intentsintents.near |
mt_on_transfer() |
本地执行成功;返回了一个 promise |
| 6 | 7wwKtfGzK1YSGqT2 |
恶意接收方dd1fe58ec316ada5 |
mt_on_transfer() |
成功;返回了退款数组 |
| 7 | 4CPmVneKa1UWEuQa |
Intentsintents.near |
mt_resolve_deposit() |
失败:日志长度超过限制 |
| 8 | 7y7VKm4tM3rEspHG |
HOT Omni Balancev2_1.omni.hot.tg |
mt_resolve_transfer() |
成功;退还了已转移的资产 |



