Back to Blog

Web3安全事件周报 | 2026年3月30日 - 4月5日

April 8, 2026
33 min read

在过去一周(2026/03/30 - 2026/04/05),BlockSec 检测并分析了九起攻击事件,估计总损失约为 2.87 亿美元。下表总结了这些事件,详细分析将在以下各节中提供。

日期 事件 类型 估计损失
2026/03/30 未知协议事件 业务逻辑缺陷 ~$10K
2026/03/30 WDGG Token 事件 访问控制 ~$40K
2026/03/31 i6Token 事件 业务逻辑缺陷 ~$273.8K
2026/04/01 Drift Protocol 事件 钓鱼攻击 ~$285.3M
2026/04/01 LML Staking Protocol 事件 业务逻辑缺陷 ~$950K
2026/04/01 Tactile 事件 价格操纵 ~$12K
2026/04/02 SAS Token 事件 业务逻辑缺陷 ~$12K
2026/04/03 Unknown-EIP-7702 事件 访问控制 ~$17.2K
2026/04/03 Silo Finance 事件 配置错误 ~$359K

1. 未知协议事件

简要概述

2026 年 3 月 30 日,BNB Chain 上一个未知协议因业务逻辑缺陷损失了约 10,000 美元。该协议将用户存款的一部分分配用于购买其平台代币 PSTART 和添加流动性,这意味着用户实际上持有受市场价格波动影响的 LP 头寸。然而,在提款时,协议并没有根据 LP 当时的实际可赎回价值进行结算。相反,它继续承诺根据历史存款和预定规则提供固定数量的稳定币。因此,攻击者通过强制投资承诺资金后,能够以预先商定的固定价值提取资金,有效地将本应由 LP 头寸承担的损失转移到协议上,最终实现零成本获利。

背景

该协议的运行方式如下:用户存入 BUSD 后,协议会自动使用一部分资金购买 PSTART,然后将其与剩余的 BUSD 配对,添加到流动性池中。由此产生的 LP 份额由 Vault 持有,同时协议在其内部账本中记录用户的一个订单,承诺每日固定收益。

之后,用户可以以固定利率领取奖励,退出时,Vault 会根据预定的规则结算本金和收益,而不是严格根据底层 LP 头寸当前的实际净资产值进行赎回。

漏洞分析

此漏洞源于协议 (0x587984...73a43c) 的不合理设计:结算逻辑脱离了底层资产的实际价值。

用户存入 BUSD 后,协议会用其中一部分购买 PSTART 并添加流动性,这意味着用户的实际底层头寸是价值随市场价格波动的 LP 敞口。然而,当用户退出时,协议并没有根据当时 LP 的实际可赎回价值进行结算。相反,它仍然承诺根据历史存款金额和预定的结算规则支付固定数量的稳定币。

攻击者利用了这一缺陷,通过使用闪电贷获得大量资金,然后反复执行 deposit()。通过这样做,攻击者迫使协议不断购买 PSTART 并改变池子的资产构成,从而人为地推高 PSTART 的价格并创造套利机会。

然后,攻击者执行 withdraw(),并以预先承诺的固定价值赎回资金,有效地将本应由底层 LP 头寸承担的损失转移到了协议本身,最终实现了零成本获利

攻击分析

以下分析基于交易 0xf3b8...55e7

  • 步骤 1: 攻击者通过闪电贷获得了约 2,000,000e18 BUSD,并在池中将其兑换为 19,013,120e18 PSTART
  • 步骤 2: 攻击者反复调用合约的 deposit() 函数来质押资金。对于每次存款,协议都会计算应使用多少 BUSD 来购买代币,以便用于添加流动性的最终代币与 BUSD 的比例更接近池子的当前比例。通过反复存款,攻击者持续向池子注入 BUSD,而 PSTART 的数量几乎没有变化。结果是 PSTART 的价值不断上涨。在此阶段,攻击者通过存款获得的 LP 实际上是以亏损购得的。
  • 步骤 3: 攻击者随后将步骤 1 中购买的 PSTART 重新卖回池子。由于步骤 2 增加了池子的 BUSD 储备,此次兑换约返还了 2,010,655e18 BUSD,在一次攻击周期中获得了约 10,655 BUSD 的利润。
  • 步骤 4: 最后,攻击者在步骤 2 中开立的所有质押头寸上执行了 withdraw()。此时,这些头寸的资产市值已经远低于其初始存款价值。根据正常的经济逻辑,无法全额赎回。然而,协议根据历史存款金额计算可赎回的 BUSD 金额,使攻击者能够在不承担任何损失的情况下全额收回所有先前强制投资的成本。

结论

此次事件的根本原因是协议将用户资金投资于受市场价格波动影响的 LP 头寸,但仍承诺根据历史存款价值和预定规则以固定数量的 BUSD 进行结算。这导致协议的负债与其底层资产的实际价值之间存在脱节。

攻击者通过反复使用 deposit() 来改变池子的资产结构并推高 PSTART 的价格,然后通过外部头寸完成套利,最后使用 withdraw() 以账面价值赎回先前亏损的头寸。这样,本应由头寸本身承担的损失就被转移到了协议上,最终实现了无风险的利润。


2. WDGG Token 事件

简要概述

2026 年 3 月 30 日,BNB Chain 上的 WDGG 代币遭到利用,导致约 40,000 美元的损失。根本原因是 burnFrom() 函数缺少访问控制。具体来说,burnFrom() 函数允许任意用户从任何地址烧毁 WDGG 代币。攻击者利用这一点,从 PancakeSwap 池中烧毁了 WDGG 代币,然后调用 sync() 函数减少池子的 WDGG 储备,并随后执行反向兑换以提取利润。

背景

此事件涉及一种代币,WDGG,它是一种分红代币,每次转账都会收取费用。

漏洞分析

WDGG 代币合约 (0x512de7...6b90c5) 在没有进行任何调用者授权的情况下暴露了 burnFrom()。因此,任何地址都可以从任何持有者(包括 PancakeSwap 池本身)烧毁 WDGG 代币。结合 PancakeSwap 可公开调用的 sync()(该函数使记录的储备与实际余额保持一致),此漏洞使得池子的 WDGG 储备可以在没有任何合法交易的情况下被任意减少,并且恒定乘积不变量被破坏,从而使池子面临价格失衡套利。

setWdgAddress() 中的第二个漏洞允许任何调用者将任意地址标记为免税,从而进一步最大化通过此攻击面可提取的利润。

攻击分析

以下分析基于交易 0x2da5...0bd1

  • 步骤 1: 攻击者首先调用 setWdgAddress() 将自己的地址设置为免税,从而允许后续转账绕过代币的转账费用。
  • 步骤 2: 攻击者随后通过 PancakeSwap 池将少量 BNB 兑换为 WDGG 代币。
  • 步骤 3: 获取 WDGG 后,攻击者调用 burnFrom() 直接从 PancakeSwap 交易对地址烧毁 WDGG 代币。
  • 步骤 4: 攻击者随后调用 sync(),强制交易对更新其储备以匹配操纵后的代币余额。结果是池中的 WDGG 储备减少到仅剩 1 wei。
  • 步骤 5: 随着池子储备严重失衡,攻击者执行反向兑换,从价格失衡中提取了利润。

结论

此次事件的根本原因是 WDGG 代币合约中 burnFrom() 函数缺少访问控制。因此,攻击者能够直接从 PancakeSwap 池中烧毁代币,通过 sync() 操纵池子的储备,并利用由此产生的价格失衡来获利。


3. i6Token 事件

简要概述

2026 年 3 月 31 日,BNB Chain 上的 i6 代币损失了约 273,800 美元,原因是 invest() 在移动池子的现货价格的同时,withdraw() 通过滞后的 TWAP 结算余额,两者可以在同一笔交易中组合。攻击者通过 invest() 膨胀现货价格,通过 withdraw() 以过时的 TWAP 赎回过量的 i6,并将 i6 卖回膨胀的池子以获利。

背景

协议的运行方式如下。当用户调用 invest() 时,USDT 被存入,并部分用于在 PancakeSwap 上购买 i6。然后,获得的 i6 与剩余的 USDT 一起被添加到 USDT/i6 池的流动性中,并且由此产生的 LP 代币被销毁。协议记录以 USDT 计价的用户和推荐人余额。

当调用 withdraw() 时,协议计算用户累计的 USDT 价值,并使用协议维护的 TWAP 价格 (twapPrice) 将其转换为 i6

漏洞分析

协议合约 (0x1cb36b...2a18a) 的根本原因在于 invest() 作为购买 i6 和添加流动性的副作用而改变了 USDT/i6 池的现货价格,而 withdraw() 使用仅在时间窗口过去后才更新的协议维护的 TWAP (twapPrice) 来结算累计的 USDT 计价余额。合约中没有任何内容阻止这两项功能在同一笔交易中运行。

由于 invest() 调用可以在同一笔交易中膨胀现货价格,而随后的 withdraw() 读取尚未更新的 TWAP,两者有效地看到了同一池子状态的两种不同价格。通过 withdraw() 赎回的 USDT 计价余额随后以过时的、低得多的价格支付为 i6,尽管每个 i6 现在在池子本身中都可以兑现更多的 USDT。这种差距将协议上任何累计的 USDT 余额变成了内部结算和实时池之间的可利用价差。

攻击分析

以下分析基于交易 0xc1b9...2f16

  • 步骤 1: 攻击者首先通过闪电贷获得了 270,000 WBNB,然后将其作为抵押品存入 Venus 并借入大量 USDT。攻击者还部署了攻击合约 A0xda49 和辅助合约 B0x096a
  • 步骤 2: 攻击合约执行了第一次 invest()。在此过程中,协议首先使用 531,489e18 USDT 购买了 234,188e18 i6,然后将 354,326e18 USDT72,607e18 i6 添加到池子中。结果,池子现货价格从约 1.05159 USDT/i6 迅速上升到约 4.89287 USDT/i6,而协议记录的 TWAP 仍然仅为 1.05159
  • 步骤 3: 攻击者随后将 124,014,184e18 USDT 转账给辅助合约 B,后者又调用 invest() 并设置 referrer = A。此步骤再次迫使协议执行大规模的 USDT -> i6 购买和 addLiquidity(),将池子储备推向了对应约 15,528 USDT/i6 现货价格的新状态。然而,由于没有新的时间窗口经过,协议并未相应地更新 TWAP
  • 步骤 4: 在第二次 invest() 完成后,作为推荐人的攻击合约 A 立即有权获得以 USDT 计价的推荐奖励。攻击者随后调用 withdraw()。协议使用过时的 TWAP 计算要支付的 i6 金额,并将代币转出其自身余额,总计支付了 5,896,508e18 i6
  • 步骤 5: 收到 i6 后,攻击者立即调用 swapExactTokensForTokensSupportingFeeOnTransferTokens 将所有 5,896,508e18 i6 卖回池子,换取 125,177,224e18 USDT。由于这些 i6 代币是使用约 1.05159 USDT/i6 的过时 TWAP 结算的,而它们是以约 15,528 USDT/i6 的价格被攻击者推高的池子现货价格出售的,因此攻击者能够直接实现这两个价格之间巨大的价差。
  • 步骤 6: 偿还闪电贷后,攻击者保留了 273,802e18 USDT,这是此次攻击的实际利润。

结论

根本原因在于一个影响现货价格的函数 (invest()) 和一个 TWAP 结算函数 (withdraw()) 可以在同一笔交易中组合,导致两者看到同一池子状态的不同价格。

为了防止此类漏洞,结合 AMM 交互和延迟定价的协议应避免在与移动底层池子现货价格的伴随函数相同的交易中以 TWAP 结算余额,而应将支付锚定在池子的实时可兑现价值上,而不是过时或派生的价格。


4. Drift Protocol 事件

简要概述

2026 年 4 月 1 日(UTC),Solana 上的 Drift Protocol 被入侵,损失约 2.853 亿美元。根本原因并非智能合约漏洞,而是多签授权流程的崩溃,加上一个 2-of-5 的安全委员会且无时间锁,以及 Solana 的持久 nonce 机制,允许预先收集的多签批准在攻击者选择执行之前一直有效。经过数周的准备,攻击者诱导五名签名者中的两人预先签署了与持久 nonce 账户绑定的恶意治理交易,随后提交这些交易以窃取管理权限,然后引入了一个伪造的抵押资产(CVT),膨胀了其预言机价格,放宽了提款限制,并通过 Drift Vault(JCNCMF...XJfrw)耗尽了真实资产。

背景

Drift Protocol 是 Solana 上的一个 DeFi 协议,支持保证金交易、借贷、现货市场和衍生品。其高权限操作,包括管理员变更、市场创建、预言机配置、风险参数更新和提款限额调整,由 Squads 多签框架而不是单一私钥管理。在攻击发生时,Drift 的安全委员会以 2-of-5 的阈值配置运行,且无时间锁,这意味着五名签名者中的任意两人都可以授权管理操作,并立即生效。该系统的安全性不仅取决于签名者密钥的保管,还取决于整个批准流程的完整性:创建了什么交易,签名者认为他们批准了什么,以及最终执行的指令是否与该审查背景相符。

另外,Solana 的持久 nonce 账户用一个存储在专用账户中的持久 nonce 替换了短暂的区块哈希,允许签名的交易在 nonce 被推进之前一直有效。该机制旨在满足合法的用例,如离线签名和延迟提交,但它通过将交易签名时间与链上执行时间分离,引入了一个关键的攻击原语。一旦签名者批准了持久 nonce 交易,除非 nonce 管理员手动推进 nonce 账户,否则该批准无法撤销。

漏洞分析

根本原因并非智能合约漏洞或密钥泄露,而是 Drift 治理配置中的三个结构性弱点,这些弱点共同将一个社会工程学机会变成了一个 2.853 亿美元的资金耗尽。首先,持久 nonce 消除了隐式的签名到期安全网。在正常的基于区块哈希的交易中,一个被欺骗的签名者的批准要么被及时执行,要么在很窄的窗口内无害地过期,从而限制了协调利用的范围。持久 nonce 消除了这一限制:一旦两名安全委员会签名者被诱导通过误导性的签名请求批准恶意的治理交易,他们的签名就可以无限期地被利用,从而使攻击者能够完全控制执行时机。

其次,管理操作的零时间锁意味着一旦提交了预先签名的交易,管理员转移就会立即生效,不留下任何检测或干预窗口。第三,管理员角色的范围足够广泛,可以在一个单一的特权路径中创建新的抵押市场、切换预言机来源并放宽提款限制,因此一次成功的治理接管就足以将任意资产转化为真实的资金提取,而无需任何进一步的授权障碍。

攻击分析

此次攻击分为三个distinct阶段:攻击前准备,攻击者进行了为期数周的操作,制造了一个假的抵押资产并通过误导性的签名请求获得了治理访问权;治理接管,攻击者快速连续提交了两笔预先签名的持久 nonce 交易来夺取管理控制权;以及资金提取,攻击者操纵了协议参数并通过协议的借贷途径耗尽了真实资产。下图说明了这三个阶段的执行流程。

  • 阶段 1(攻击前准备): 从 3 月 11 日开始,攻击者从 Tornado Cash 提取了 10 个 ETH,部署了 CarbonVote Token(CVT),铸造了 7.5 亿单位,然后在 Raydium 上注入流动性,并通过冲洗交易将价格历史推高至接近 1 美元。同时,截至 3 月 23 日,已创建了四个持久 nonce 账户,其中两个与 Drift 安全委员会成员关联,两个由攻击者控制,这表明至少有五名签名者中的两人已经签署了与持久 nonce 账户相关的交易。3 月 27 日,由于成员变动,Drift 执行了计划中的安全委员会迁移,使先前收集的签名失效;然而,截至 3 月 30 日,攻击者在新配置下重新获得了所需的阈值,这表明了对链上治理变化的积极监控和实时适应。
  • 阶段 2(治理接管): 4 月 1 日约 16:05 UTC,在 Drift 执行了一次合法的保险基金测试提款后约一分钟,攻击者在相隔四个槽位的地方提交了两笔预先签名的持久 nonce 交易。第一笔交易(2HvMSg...2C4H)创建并批准了恶意的管理员转让提案。第二笔交易(4BKBmA...RsN1)批准并执行了该提案,从 AdvanceNonceAccount 开始激活存储的 nonce,接着是 proposalApprovevaultTransactionExecute,最终调用 UpdateAdmin 将管理控制权转移到攻击者控制的地址。
  • 阶段 3(资金提取): 获得完全的管理权限后,攻击者为 CVT 创建了一个抵押品市场,切换到攻击者控制的预言机以膨胀其账面价格,并提高了或取消了主要资产市场的提款限制。随后,攻击者向协议中存入了大量被高估的 CVT,并在大约 12 分钟内执行了 31 次快速提款,耗尽了 USDCJLPSOLcbBTCUSDTwETHdSOLWBTCJTOFARTCOIN,总损失约 2.853 亿美元,计算基于攻击者的提款账户(HkGz4K...pZES)。

结论

此次事件的根本原因并非智能合约漏洞或密钥泄露,而是多签授权流程的崩溃,加上持久 nonce 驱动的延迟执行和零时间锁的管理路径。通常会在几分钟内过期的预先收集的批准可以无限期地被利用,一旦提交,管理员接管和随后的资金提取就没有留下干预窗口。

减轻此类风险需要确保整个授权流程的安全性,而不仅仅是签名者密钥的保管;对高权限操作强制执行时间锁;并将持久 nonce 等延迟执行机制视为一个独立的威胁表面,需要更高的签名阈值、限时或可撤销的批准,以及对无限期有效签名交易的限制。


5. LML Staking Protocol 事件

简要概述

2026 年 4 月 1 日,BNB Chain 上的 LML 质押协议被利用,损失约 950,000 美元。根本原因是奖励计算逻辑中的不一致:奖励兑换读取一个存储的 LML/USDT 价格,该价格被锁定在 3600 秒的更新冷却时间内,而支付的 LML 可以以实时 AMM 价格赎回,两者之间没有偏差检查。攻击者使用闪电贷来膨胀池子现货价格,并使用 EIP-7702 代码委托来一次性批量领取 11 个预先质押的 EOA 的奖励,以过时的存储价格获得了超额的 LML,并通过严重失衡的池子将其卖回以获利。

背景

LML 是 BNB Chain 上的一个质押协议,用户通过 APower 合约质押 BNB 来赚取 LML 代币作为奖励。奖励以 USDT 计价计算,然后根据协议存储的 LML/USDT 价格转换为 LML 金额后再分配。存储价格通过 updatePrice() 刷新,该函数读取 AMM 现货价格,但强制执行3600 秒的冷却时间才能更新。奖励领取通过 APowerreceive()msg.sender 为基础触发,因此只有原始质押地址才能领取自己的奖励。

漏洞分析

质押合约 (0xbe9713...adce19) 的核心缺陷在于奖励累积和奖励赎回锚定在同一池子的两个不同价格上,而没有进行一致性检查。奖励公式 reward += (10^18 * base_reward) / stored_price 计算 LML 的支付,该支付来自 _prices[],这是一个协议存储的 LML/USDT 价格,仅在 updatePrice() 执行 3600 秒冷却后刷新,然而支付的 LML 可以立即以实时 AMM 现货价格赎回。任何在冷却窗口内移动现货价格的外部活动都会打开一个冻结的累积价格和一个实时卖出价格之间的差距,而当这个差距变得不合理时,合约中没有任何内容会拒绝领取。

第二个结构性缺陷在于奖励来源的补充方式。当 PROOF 合约的 LML 余额不足以支付领取时,swapBack() 通过调用 super._transfer(swapPair, PROOF, deficit) 然后调用 sync() 来补充它,直接将 LML 从 LP 交易对的储备中移出,并重新对齐交易对的存储状态,而不是通过正常的兑换。由于此路径绕过了交易对的价格发现,每次触发此操作的领取都会减少交易对的 LML 储备并进一步改变现货价格,而没有相应的代币流入,因此重复领取会机械地扩大冻结的存储价格和实时卖出价格之间的差距。

攻击分析

以下分析基于交易 0x805d...5b470x70f7...3572

  • 步骤 1: 攻击者通过 Moolah 的闪电贷汇集了大量 USDTWBNB,从 Venus 和 Moolah Pool 借款(使用 WBNB 作为抵押品),以及从 PancakeSwap V4、多个 V3 池和 V2 池进行闪电贷。需要这些资金来操纵 LML/USDT 交易对价格。
  • 步骤 2: 攻击者调用 LML 代币合约上的 swapAndTrans(),将合约中累积的 LML 费用兑换成 USDT。这耗尽了 LML 合约自身的 LML 余额,意味着它不再能作为本地代币来源,任何后续的奖励分配都需要通过 swapBack() 从 LP 交易对中提取 LML
  • 步骤 3: 攻击者通过 PancakeRouter swapExactTokensForTokensSupportingFeeOnTransferTokensUSDT 兑换成 LML,接收者设置为死地址。购买的 LML 代币被销毁,而不是由攻击者接收。唯一目的是耗尽交易对中的 LML 并膨胀 AMM 上的 LML 价格,攻击者不需要代币本身,只需要价格扭曲。
  • 步骤 4: 攻击者之前已使用 11 个 EOA 地址存入了质押协议。由于 APower 的 receive() 基于 msg.sender 触发 _claimReward(msg.sender),奖励只能由存款地址本身领取。为了在单笔交易中领取所有 11 个 EOA 的奖励,攻击者使用了 EIP-7702 在这些 EOA 上设置代码,使它们能够作为合约被攻击者的主合约调用。每个 EOA 执行了一个 transfer(rst, fte) 函数,将少量 BNB 发送到 APower,触发 receive()_claimReward(EOA)。在每次领取中:updatePrice() 被跳过(未满足 3600 秒冷却时间,因此 stored_price 仍保持历史低值),updateUser() 使用过时的低价计算奖励,sendMining()LML 从 PROOF 转移到 APower,然后触发 swapBack(),后者通过从 LP 交易对中提取 LML 并调用 sync() 来补充 PROOF,进一步减少了交易对的储备。最后 claimReward()LML 分配给 EOA,并且每个 EOA 将收到的 LML 转回攻击合约。
  • 步骤 5: 攻击者通过现在严重枯竭的池子,以极度膨胀的价格将累积的 LML 兑换回 USDT
  • 步骤 6: 偿还所有闪电贷、借款和费用。转移剩余利润。

结论

根本原因是质押合约中奖励累积和赎回不匹配:支付的金额基于一个被 3600 秒冷却时间锁定的存储 LML/USDT 价格,但以 LML 结算,其真实价值追踪实时 AMM 价格,两者之间没有偏差检查。swapBack() 补充路径通过在每次领取时直接从 LP 交易对中耗尽 LML 来放大此缺陷,机械地扩大冻结存储价格和实时卖出价格之间的差距,处理的领取越多,差距越大。

从 AMM 派生价格中计算奖励的质押协议,在领取时应强制执行存储价格与当前现货价格之间的偏差检查,并在差距超过安全阈值时回滚,并应避免使用会改变 LP 储备(在正常兑换路径之外)的补充机制,因为这些机制会绕过价格发现,而价格发现本可以限制过时定价造成的损害。


6. Tactile 事件

简要概述

2026 年 4 月 1 日,Polygon 上的分级存款协议 Tactile 损失了约 12,000 美元。根本原因是其存款和提款结算逻辑中的不一致:入场和出场都根据 CES 的现货价格进行结算,而内部份额没有任何关于其最初铸造时资产价值的记录。攻击者利用这一点,在存款前膨胀现货价格以获得超额份额,然后在提款前压低价格以每份额兑换更多 CES,并通过辅助合约重复该循环以提取利润。

背景

Tactile 是 Polygon 上的一个分级存款协议,用户根据所选级别将 CES 存入支付合约。所需的存款金额根据 CES 的当前现货价格和级别配置计算,用户将获得代表其头寸的内部记账份额。提款时,记录的份额会根据退出时的现货价格兑换回 CES,而不是根据最初存入的金额进行结算,因此用户余额实际上是作为价格依赖的记账单位来跟踪的,而不是固定的资产金额。

漏洞分析

支付合约 (0x9153e1...09b654) 的核心缺陷在于存款和提款在两个不同的时间点针对同一现货价格预言机进行结算,而没有任何不变的锚定将它们联系起来。存款时,合约读取 getActualPrice() 并根据当前价格将存入的 CES 兑换成内部份额;提款时,相同的份额会使用赎回时的现货价格兑换回 CES

由于份额本身不携带关于其铸造时价格或资产金额的记录,因此在这两个时间点之间现货价格的任何变动都会直接导致存入的 CES 和支出的 CES 之间的不匹配,使得协议的记账完全暴露于价格路径而不是底层资产价值。

攻击分析

以下分析基于交易 0xc321...da74

  • 步骤 1: 攻击者首先从 Uniswap V3 闪电池借入了 55,365e18 CES,并将资金分配给 5 个辅助合约。每个辅助合约首先收到 6,426e18 CES,然后调用 deposit(12)。在此过程中,每个辅助合约首先查询 getPriceForLevel(12),然后根据当前价格准备此存款所需的 CES 金额。
  • 步骤 2: 在所有 5 个辅助合约完成第一轮 deposit 后,攻击者在 DEX 上倾销了 300,000 CES,将 bank 使用的价格从 1.067585 推低至 0.688542。然后,5 个辅助合约逐一执行 withdraw,以较低的价格将先前以高价创建的份额赎回为 CES。每个辅助合约收到 9,427e18 CES
  • 步骤 3: 完成第一轮 withdraw 后,攻击者将获得的对手方资产兑换回 CES,再次推高价格。然后攻击者重复步骤 2-3。
  • 步骤 4: 最后,在多次攻击周期后,并偿还了闪电贷以及 166.097975017841805126 CES 的闪电费后,攻击者剩余了 567,736e18 CES 作为利润。

结论

此次事件的根本原因是 Tactile 在存款和提款结算时都依赖于可操纵的现货价格,并且没有将记账份额锚定在存款时的资产金额或价格上,使得其内部记账完全暴露于进出之间的任何价格变动。

发行针对波动性资产的份额类头寸的协议应将每个份额锚定在铸造时的具体资产金额或价格上,以便赎回能够重现原始经济价值,而不是根据实时预言机重新定价。在结算函数必须引用当前价格的情况下,它们应使用抗操纵的时间加权或以其他方式抗操纵的来源,并避免读取在同一交易中可以被结算调用移动的现货价格。


7. SAS Token 事件

简要概述

2026 年 4 月 2 日,BNB Chain 上的 SAS 代币被利用,损失约 12,000 美元。根本原因是代币自定义转账逻辑中的一个缺陷:将 SAS 发送到 LP 池仅会增加一个全局 sellBurn 计数器,并且任何后续的普通转账随后就可以直接从池子中烧毁 SAS 并调用 sync() 来重写其储备,这一切都无需经过 AMM 的兑换逻辑。攻击者利用这一点,通过出售累积 sellBurn,触发了一次不相关的普通转账来烧毁池子中的 SAS 并将其储备推至 1 wei,然后通过反向兑换剩余的 SAS 来获利。

背景

SAS 是 BNB Chain 上的一种通缩代币,其自定义转账逻辑构建在 PancakeSwap V2 池之上。其 transfer() 函数区分两种路径:一种是卖出路径,当转账目的地是 LP 池时触发,该路径将转账金额增加到一个全局 sellBurn 累加器;另一种是普通转账路径,当 sellBurn 非零时,该路径会直接从 LP 池中烧毁 SAS,然后调用 sync() 来更新其储备以匹配新的链上余额。这两种路径旨在共同作用,作为一种通缩机制,以响应累积的卖出压力来减少池子的 SAS 储备。

漏洞分析

SAS 代币合约 (0xbfa266...3d91c6) 的核心缺陷在于通缩机制如何被整合到 transfer() 中。当 SAS 被发送到 LP 池时,合约会增加一个全局 sellBurn 累加器,金额为转账金额。然后,在任何后续的普通转账中,如果 sellBurn 非零,合约会调用 _burnFromPair() 直接从 LP 池中烧毁 SAS,并紧接着调用 sync(),后者会将池子储备重写为与链上余额匹配。

问题在于,这种烧毁并同步的路径会在不经过 AMM 兑换逻辑的情况下重写池子储备。一旦 sellBurn 被推高(通过转账到池子),一次不相关的普通转账就足以触发烧毁和同步,将池子的 SAS 储备推向零,并造成巨大的价格扭曲,然后可以通过普通兑换来获利。

攻击分析

以下分析基于交易 0x878e...adc5

  • 步骤 1: 攻击者通过闪电贷借入了 WBNB
  • 步骤 2: 攻击者将 WBNB 兑换成 SAS
  • 步骤 3: 攻击者部署了一个合约,并在其 constructor() 中执行了攻击逻辑。这是为了绕过协议的 is_contract() 检查,因为代币合约要求 transfer() 的发送方是一个白名单地址或 EOA。
  • 步骤 4: 攻击者将 SAS 转账到池子,这触发了卖出路径并累积了 sellBurn
  • 步骤 5: 攻击者部署了第二个合约,同样在其 constructor() 中,发起了一次普通转账。由于步骤 4 已经使 sellBurn 非零,这次转账触发了 _burnFromPair() 函数,该函数直接从 LP 池烧毁了 SAS,然后调用 sync() 函数,将 SAS 储备减少到 1 wei。
  • 步骤 6: 攻击者执行反向兑换,将剩余的 SAS 卖出获利。

结论

此事件的根本原因是 SAS 代币自定义转账逻辑中的一个缺陷:普通转账可以直接从 LP 池烧毁 SAS 并同步其储备到减少的余额,使得累积的卖出活动能够任意减少池子的 SAS 储备,并从中产生巨大的价格扭曲,然后可以通过普通兑换来获利。

代币不应直接操作外部 AMM 池并修改其储备,而应在正常的兑换路径之外进行。如果通缩设计确实需要从池子中烧毁代币,那么烧毁和伴随的 sync() 必须绑定到一个严格控制的内部触发器,例如受信任的 Keeper 或限速计划,而不是搭便车到任意用户转账。


8. Unknown-EIP-7702 事件

简要概述

2026 年 4 月 3 日,BNB Chain 上一个启用了 EIP-7702 委托代码的用户账户被耗尽了约 17,200 美元。委托代码暴露了一个没有适当访问控制的 pancakeV3SwapCallback() 函数。攻击者直接调用了这个回调函数,并使用了精心构造的 calldata,迫使受害者账户将其代币转账到一个由攻击者控制的地址。

背景

受害者 EOA 使用 EIP-7702 Type-4 交易设置了委托代码,以便账户能够执行与兑换相关的逻辑。然而,委托实现包含一个公共 pancakeV3SwapCallback() 函数,该函数仅应在合法的 PancakeSwap V3 池回调期间被调用。

漏洞分析

根本原因是委托合约 (0x02C809...aEDbAE) 的 pancakeV3SwapCallback() 函数缺少访问控制。

在正确的 UniswapV3/PancakeV3 回调设计中,回调必须验证 msg.sender 是否是预期的规范池(从工厂 + 代币对 + 费用派生,或与受信任的池列表进行验证)。在此案例中,缺少该验证,因此任何外部调用者都可以直接调用回调。

由于回调执行从托管该回调的账户进行的代币转账,缺少 msg.sender 检查意味着任何带有正 amount0Delta/amount1Delta 的外部调用都会进入回调内的支付路径,并将代币移出受害者账户,而实际上没有任何兑换发生。

攻击分析

以下分析基于交易 0x5b2c...4261

  • 步骤 1: 攻击者直接调用 pancakeV3SwapCallback() 并传入精心构造的参数,触发回调转账逻辑,将受害者的代币转移到攻击者控制的地址。

结论

此事件是由在 EIP-7702 账户中部署的、未经严格回调身份验证的兑换回调逻辑引起的。由于 pancakeV3SwapCallback() 缺少访问控制,回调可以被任何外部调用者调用,并用于将代币移出受害者账户,而无需发生合法的兑换。

对于任何实现 V3 风格回调的合约或委托的 EIP-7702 代码,开发者必须在回调进入任何转账逻辑之前,验证 msg.sender 是否是规范的 PancakeV3 池(从受信任的工厂、代币对和费用等级派生)。


9. Silo Finance 事件

简要概述

2026 年 4 月 3 日,Arbitrum 上的 Silo Finance soUSDC 金库被利用,损失约 359,000 美元。根本原因是三个缺陷的汇合:一个不可变的 wstUSR 预言机,在其市场价格已跌至约 0.12 美元后,仍将其定价为约 1.133 美元;soUSDC 的供应上限机制仅限制金库自身的存款,而不限制外部存款;以及一个 totalAssets() 记账缺陷,该缺陷在未铸造相应 soUSDC 份额的情况下,计算了外部存入的 bUSDC 份额。通过直接将 USDC 存入零上限的 wstUSR 市场(receiver=soUSDC),攻击者膨胀了金库的份额价格,以过高估值的 wstUSR 抵押品借回相同的 USDC,并以膨胀的估值赎回先前获得的 soUSDC 份额,差额从提款队列中的其他健康市场中提取。

背景

Silo Finance 是 Arbitrum 上的一个风险隔离借贷协议。每个 Silo 市场都是一个双向借贷对(例如 wstUSR/USDC):借款人存入抵押品(wstUSR)并借入贷出资产(USDC),而贷方存入 USDC 并赚取利息。当贷方将 USDC 存入特定市场时,他们会收到该市场的存款份额代币。当借款人存入抵押品时,他们会收到抵押品份额代币(例如 bwstUSR-149)。

soUSDC 是一个 SiloVault,它建立在多个 Silo 市场之上,用于聚合 USDC 借贷。用户将 USDC 存入 soUSDC 并收到 soUSDC 份额。然后,金库根据分配器设置的供应上限将存入的 USDC 分配到批准的 Silo 市场,金库本身持有其已存入的每个市场的 bUSDC 份额。当用户赎回 soUSDC 份额时,金库使用 totalAssets() 计算份额的 USDC 价值,该函数会遍历提款队列中的每个市场,并汇总金库在每个市场中的 bUSDC 份额余额。然后,金库从其底层市场提取 USDC 来支付赎回者。

wstUSR(Wrapped Staked USR)是 Resolv 发行的 USR 稳定币的质押衍生品。在 Resolv 被利用后,USR 脱锚,stUSR 也失去了其锚定,wstUSR 的二级市场价格跌至约 0.12 美元。然而,Chainlink 的 wstUSR 价格源仅追踪 wstUSR/stUSR 汇率(约 1.133),并且协议隐式假设 1 stUSR = 1 美元,因此预言机继续将 wstUSR 定价为约 1.133 美元,与市场现实存在约 10 倍的差距。

漏洞分析

wstUSR/USDC 市场的预言机地址已在 SiloConfig 中硬编码为不可变,无法替换。预言机合约本身(0x836a1a...04425e)是一个 ChainlinkV3Oracle,其底层 Chainlink 价格源(描述:“wstUSR / stUSR Exchange Rate”)仅追踪 wstUSRstUSR 的包装比率(约 1.133),而非二级市场价格。协议隐式假设 1 stUSR = 1 美元,因此将 wstUSR 定价为约 1.133 美元。在 USR 脱锚后,stUSR 也失去了其锚定,wstUSR 在公开市场崩跌至约 0.12 美元,但预言机继续报告约 1.133 美元,高估了约 10 倍。

协议部分意识到风险:soUSDCwstUSR 市场的供应上限设置为 0,意味着金库永远不会主动将 USDC 路由到其中。然而,此上限仅管辖金库自身的出站 deposit() 调用。由于 wstUSR_Market.deposit() 接受任意的 receiver 参数,任何人都可以将 USDC 直接存入 wstUSR 市场并将其产生的 bUSDC 份额记入 soUSDC 的地址,从而完全绕过供应上限。

这创造了核心的利用路径。当 bUSDC 份额通过此类外部存款进入 soUSDC 的余额时,totalAssets() 会将其计算在内:它遍历提款队列中的每个市场,并读取金库的实际份额余额,而没有检查该头寸是否是自愿进入的。同时,由于金库自身的铸造逻辑从未被调用,因此不会为这些外部计入的头寸铸造新的 soUSDC 份额。结果是 totalAssets 增加,而 totalShares 保持不变,从而膨胀了 soUSDC 的份额价格。

攻击分析

以下分析基于交易 0xf77a...f3e1

攻击者首先在二级市场以每枚约 0.12 美元的价格购买了 wstUSR

  • 步骤 1: 从 Morpho 闪电贷约 4,236,352 USDC。仅靠预言机定价错误是不够的——wstUSR 市场没有 USDC 流动性(上限=0,soUSDC 从未存入其中),因此没有东西可以以高估的抵押品进行借贷。闪电贷提供了后续存款和捐赠步骤所需的资金。
  • 步骤 2:wstUSR 作为抵押品存入 wstUSR 市场,并获得 bwstUSR-149。这是为步骤 5 的借贷做准备——预言机将 13,797 wstUSR 定价为约 15,633(每枚 1.133 美元),即使攻击者仅支付了约 1,656。
  • 步骤 3: 将约 4,222,007 USDC 存入 soUSDC 金库,获得 soUSDC 份额(约占总供应量的 91.5%)。金库将此 USDC 路由到现有的健康市场(而非 wstUSR 市场,因为上限=0)。这些 soUSDC 份额是步骤 6 中提取利润的工具——攻击者持有的份额越多,在份额价格膨胀时收益越大。
  • 步骤 4: 通过 wstUSR_Market.deposit(receiver=soUSDC) 将约 14,344 USDC 直接存入 wstUSR 市场,并为 soUSDC 铸造 bUSDC-149。产生的 bUSDC 份额被记入 soUSDC 的地址,而非攻击者。这是核心的操纵:soUSDCtotalAssets() 现在包括这些面值为约 14,344 USDCbUSDC 份额,但没有新的 soUSDC 份额被铸造,因为金库自身的存款逻辑从未被调用——totalAssets 增加,totalShares 保持不变,soUSDC 份额价格膨胀。同时,这在之前空的 wstUSR 市场中产生了 USDC 流动性,这是下一步所必需的。
  • 步骤 5: 使用步骤 2 中存入的抵押品,从 wstUSR 市场借入约 14,344 USDC。预言机将抵押品定价为约 15,633,因此在 92% 的最大 LTV 下,攻击者可以借入约 14,344。这回收了步骤 4 中捐赠的 USDC——借贷和捐赠在现金流上是中性的。但 wstUSR 市场现在已完全枯竭:所有 USDC 都被借出,只留下由几乎毫无价值的 wstUSR 抵押品支持的未偿还贷款。soUSDC 仍在其 totalAssets() 中持有面值为 bUSDC 份额。
  • 步骤 6: 赎回步骤 3 中获得的所有 soUSDC 份额。由于步骤 4 的捐赠,份额价格现在已膨胀,因此攻击者收到了约 4,235,143 USDC,比步骤 3 中存入的 4,222,007 多了约 13,136。金库尝试从 wstUSR 市场提取,但发现没有流动性(在步骤 5 中被借出),因此它从提款队列中的其他健康市场提取了差额。损失在此处显现:来自其他 soUSDC 存款者市场的真实 USDC 被转移以弥补膨胀的赎回。
  • 步骤 7: 偿还闪电贷。

经过 32 次循环后,soUSDC 留下了 wstUSR 市场中的 bUSDC 头寸,其面值为约 359,000 美元,但由价值仅为该金额一小部分的 wstUSR 抵押品支持——100% 的利用率,实际上是不可回收的坏账,由剩余的 soUSDC 存款人承担。

结论

此次事件是由追踪质押汇率而非脱钩资产市场价格的预言机、在未铸造相应份额的情况下计算外部存入份额的 totalAssets() 记账系统,以及仅限制金库自身存款而不限制外部存款的供应上限机制的汇合引起的。SiloConfig 中不可变的预言机地址阻止了在问题显现后进行任何紧急修复。

在多个借贷市场之间进行聚合的金库协议应确保 totalAssets() 仅计算金库通过自身存款操作进入的头寸,而不是外部计入的份额余额。预言机地址不应永久不可变;当底层资产脱钩时,应存在用于价格源更新的紧急治理机制。

Sign up for the latest updates
Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure
Case Studies

Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure

An on-chain investigation into VerilyHK, a fraudulent platform that moved $1.6B in TRON USDT through a multi-layered fund-routing infrastructure of rotating wallets, paired payout channels, and exchange exit funnels, with traced connections to the FinCEN-sanctioned Huione Group.

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026

This BlockSec weekly security report covers nine DeFi attack incidents detected between March 30 and April 5, 2026, across Solana, BNB Chain, Arbitrum, and Polygon, with total estimated losses of approximately $287M. The week was dominated by the $285.3M Drift Protocol exploit on Solana, where attackers combined multisig signer social engineering with Solana's durable nonce mechanism to bypass a zero-timelock 2-of-5 Security Council, alongside notable incidents including a $950K flash loan TWAP manipulation against the LML staking protocol, a $359K Silo Finance vault inflation via an external `wstUSR` market donation exploiting a depegged-asset oracle and `totalAssets()` accounting flaw, and an EIP-7702 delegated-code access control failure. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident, covering flawed business logic, access control, price manipulation, phishing, and misconfiguration attack types.

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation
Security Insights

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation

On April 1, 2026 (UTC), Drift Protocol on Solana suffered a $285.3M loss after an attacker exploited Solana's durable nonce mechanism to delay the execution of phished multisig approvals, ultimately transferring administrative control of the protocol's 2-of-5 Squads governance with zero timelock. With full admin privileges, the attacker created a malicious collateral market (CVT), inflated its oracle price, relaxed withdrawal protections, and drained USDC, JLP, SOL, cbBTC, and other assets through 31 rapid withdrawals in approximately 12 minutes. This incident highlights how durable nonce-based delayed execution can decouple signer intent from on-chain execution, bypassing the temporal assumptions that multisig security implicitly relies on.