在上周(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 |
Web3 最佳安全审计师
在上线前验证设计、代码和业务逻辑
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,000e18BUSD,并在池中兑换成19,013,120e18PSTART。 -
步骤 2:攻击者反复调用合约的
deposit()函数进行质押。每次存款,协议都会计算应使用多少BUSD购买代币,以使用于添加流动性的最终代币与BUSD的比例更接近池子的当前比例。通过反复存款,攻击者持续将BUSD注入池中,而PSTART的数量几乎保持不变。结果是PSTART的价值不断上涨。在此阶段,攻击者通过存款获得的LP实际上是以亏损获得的。 -
步骤 3:攻击者随后将步骤 1 中购买的
PSTART卖回池中。由于步骤 2 增加了池子的BUSD储备,这次兑换带来了约2,010,655e18BUSD,在一次攻击周期中产生了约10,655 BUSD的利润。 -
步骤 4:最后,攻击者对步骤 2 中打开的所有质押头寸执行了
withdraw()。此时,这些头寸对应的资产的市场价值已经远低于其初始存款价值。根据正常的经济逻辑,不应进行全额赎回。然而,协议根据历史存款金额计算可赎回的BUSD金额,允许攻击者完全收回所有先前强制投资的成本,而无需承担任何损失。

结论
此事件的根本原因在于,该协议将用户资金投资于受市场价格波动影响的 LP 头寸,但仍承诺根据历史存款价值和预定义规则以固定数量的 BUSD 进行结算。这导致协议的负债与其底层资产的实际价值之间脱节。
攻击者利用了这一缺陷,通过反复使用 deposit() 来改变池子的资产结构并推高 PSTART 的价格,然后通过外部头寸完成套利,最后使用 withdraw() 以账面价值赎回先前亏损的头寸。通过这种方式,本应由头寸本身承担的损失被转移到协议上,最终实现了无风险利润。
2. WDGG Token 事件
摘要
2026 年 3 月 30 日,BNB Chain 上的 WDGG token 被利用,导致约 40,000 美元的损失。根本原因在于 burnFrom() 函数缺少访问控制。具体来说,burnFrom() 函数允许任意用户烧毁来自任何地址的 WDGG token。攻击者通过烧毁 PancakeSwap 池中的 WDGG token,然后调用 sync() 函数来减少池子的 WDGG 储备,随后执行反向兑换以提取利润。
背景
此事件涉及单一 token WDGG,它是一种分红 token,每次转账都会收取费用。
漏洞分析
WDGG token 合约(0x512de7...6b90c5)在没有任何调用者授权的情况下暴露了 burnFrom()。因此,任何地址都可以烧毁任何持有者的 WDGG token,包括 PancakeSwap 池本身。与 PancakeSwap 公开可调用的 sync()(用于将记录的储备金与实际余额对齐)结合,这一缺陷使得池子的 WDGG 储备可以被任意减少,并且在没有任何合法交易的情况下打破了恒定乘积不变性,使池子容易受到价格不平衡套利的影响。

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

攻击分析
以下分析基于交易 0x2da5...0bd1。
- 步骤 1:攻击者首先调用
setWdgAddress()将自己的地址设置为免税,允许后续转账绕过 token 的转账费用。

-
步骤 2:然后,攻击者通过 PancakeSwap 池将少量
BNB兑换成WDGGtoken。 -
步骤 3:获得
WDGG后,攻击者调用burnFrom()直接从 PancakeSwap 对地址烧毁WDGGtoken。 -
步骤 4:攻击者随后调用
sync(),强制对将储备金更新为与操纵的 token 余额匹配。结果是池中的WDGG储备减少到仅 1 wei。

- 步骤 5:池子储备金严重失衡后,攻击者执行反向兑换,从价格不平衡中提取利润。

结论
此事件的根本原因在于 WDGG token 合约的 burnFrom() 函数中缺少访问控制。因此,攻击者能够直接从 PancakeSwap 池中烧毁 token,通过 sync() 操纵池子储备金,并利用由此产生的价格不平衡来获利。
3. i6Token 事件
摘要
2026 年 3 月 31 日,BNB Chain 上的 i6 Token 因 invest() 移动了池子的现货价格,而 withdraw() 通过滞后的 TWAP 结算余额,两者可以在同一笔交易中组合使用,损失约 273,800 美元。攻击者通过 invest() 抬高了现货价格,通过 withdraw() 以过时的 TWAP 赎回了过量的 i6,然后将 i6 卖回给被抬高的池子以获利。
背景
该协议如下运行。当用户调用 invest() 时,USDT 被存入,部分用于在 PancakeSwap 上购买 i6。然后,获得的 i6 与剩余的 USDT 一起作为流动性添加到 USDT/i6 池中,并将生成的 LP token 烧毁。协议以 USDT 计价记录用户和推荐人的余额。
当调用 withdraw() 时,协议以 USDT 计价计算用户的累积价值,并使用协议维护的 TWAP 价格(twapPrice)将其转换为 i6。
漏洞分析
协议合约(0x1cb36b...2a18a)中的根本原因在于 invest() 作为购买 i6 和添加流动性的副作用改变了 USDT/i6 池的现货价格,而 withdraw() 使用协议维护的 TWAP(twapPrice)以 USDT 计价结算累积余额,该 TWAP 仅在时间窗口过后更新。合约中没有任何内容阻止这两项功能在同一笔交易中运行。
由于 invest() 调用可以在后续 withdraw() 读取尚未更新的 TWAP 的同一笔交易中影响现货价格,两者实际上看到了同一池状态的两种不同价格。通过 withdraw() 赎回的 USDT 计价余额随后以过时的、低得多的价格支付为 i6,即使每个 i6 本身在池中现在可以兑换更多的 USDT。这种差距将协议上任何累积的 USDT 余额变成了内部结算与实时池之间可利用的价差。
攻击分析
以下分析基于交易 0xc1b9...2f16。
-
步骤 1:攻击者首先通过闪电贷获得了
270,000 WBNB,然后将其作为抵押品存入 Venus 并借入了大量USDT。攻击者还部署了攻击合约 A 在0xda49,以及辅助合约 B 在0x096a。 -
步骤 2:攻击合约执行了第一次
invest()。在此过程中,协议首先使用531,489e18USDT购买了234,188e18i6,然后将354,326e18USDT与72,607e18i6一起添加到池中。结果,池子现货价格从约1.05159 USDT/i6迅速上涨到约4.89287 USDT/i6,而协议记录的TWAP仍然只保持在1.05159。

-
步骤 3:攻击者随后将
124,014,184e18USDT转入辅助合约 B,后者调用invest()并指定referrer = A。此步骤再次迫使协议执行大量的USDT -> i6购买和addLiquidity(),将池子储备金推至对应于约15,528 USDT/i6现货价格的新状态。然而,由于没有新的时间窗口经过,协议没有相应地更新TWAP。 -
步骤 4:第二次
invest()完成后,攻击合约 A 作为推荐人,立即有权获得以USDT计价的推荐奖励。攻击者随后调用withdraw()。协议使用过时的TWAP计算要支付的i6金额,并将 token 从其自有余额中转出,总共支付了5,896,508e18i6。 -
步骤 5:收到
i6后,攻击者立即调用swapExactTokensForTokensSupportingFeeOnTransferTokens,将所有5,896,508e18i6卖回给池子,换取125,177,224e18USDT。由于这些i6token 是使用约1.05159 USDT/i6的过时 TWAP 结算的,而在池子现货价格(被攻击者推高至约15,528 USDT/i6)下卖出,攻击者能够直接实现这两个价格之间的巨大价差。 -
步骤 6:偿还闪电贷后,攻击者保留了
273,802e18USDT,这是攻击的实际利润。
结论
根本原因是影响现货价格的函数(invest())和通过 TWAP 结算的函数(withdraw())可以在同一笔交易中组合使用,导致两者看到同一池状态的不同价格。
为了防止此类漏洞,结合了 AMM 交互和延迟定价的协议应避免在同一笔交易中结算余额(使用 TWAP)以及伴随函数移动底层池的现货价格,而应将付款锚定在池子的实时可实现价值,而不是过时或派生的价格。
4. Drift Protocol 事件
摘要
2026 年 4 月 1 日(UTC),Solana 上的 Drift Protocol 被入侵,损失约 2.853 亿美元。根本原因并非智能合约 bug,而是多签授权流程的崩溃,再加上一个 2/5 的安全委员会没有时间锁,以及 Solana 的持久 nonce 机制,使得预先收集的多签批准保持有效,直到攻击者选择执行。经过数周的准备,攻击者诱使五名签名者中的两人预先签署了与持久 nonce 账户绑定的恶意治理交易,随后提交这些交易以窃取管理员控制权,然后引入了一个伪造的抵押品资产(CVT),抬高了其预言机价格,放宽了提款限制,并通过 Drift Vault(JCNCMF...XJfrw)提取了真实资产。
背景
Drift Protocol 是 Solana 上的一个 DeFi 协议,支持保证金交易、借贷、现货市场和衍生品。其高权限操作,包括管理员更改、市场创建、预言机配置、风险参数更新和提款限制调整,均由 Squads 多签框架管理,而非单个私钥。攻击发生时,Drift 的安全委员会采用 2/5 的阈值配置,没有时间锁,这意味着五名签名者中的任何两人都可以立即授权行政操作。该系统的安全性不仅取决于签名者密钥的保管,还取决于整个批准流程的完整性:创建了什么交易,签名者认为他们批准了什么,以及最终执行的指令是否与该审查上下文相符。
另外,Solana 的持久 nonce 账户用一个专用账户中存储的持久 nonce 替换了短暂的区块哈希,允许已签名的交易在 nonce 被推进之前无限期有效。该机制是为了合法的用例(如离线签名和延迟提交)而设计的,但它通过将交易签名的时间与链上执行的时间脱钩,引入了一个关键的攻击原语。一旦签名者批准了持久 nonce 交易,该批准就无法撤销,除非 nonce 管理员手动推进 nonce 账户。
漏洞分析
根本原因并非智能合约 bug,而是 Drift 治理配置中的三个结构性弱点,这些弱点共同将一个社交工程机会变成了一个 2.853 亿美元的资金提取。首先,持久 nonce 消除了隐含的签名过期安全网。在正常的基于区块哈希的交易中,被欺骗的签名者的批准要么被及时执行,要么在狭窄的时间窗口内无害地过期,从而限制了协同利用的范围。持久 nonce 消除了这种限制:一旦两名安全委员会签名者被诱骗通过误导性的签名请求批准了恶意的治理交易,他们的签名就可以被无限期地利用,从而使攻击者完全控制执行时机。
其次,行政操作的零时间锁意味着一旦提交了预先签名的交易,管理员转移就会立即生效,没有检测或干预的窗口。第三,管理员角色的范围足够广泛,可以在一个特权路径中创建新的抵押品市场、切换预言机来源和放宽提款限制,因此一次成功的治理接管就足以将任意资产转换为真实资金提取,而无需进一步的授权障碍。
攻击分析
攻击分三个不同阶段展开:攻击前准备,攻击者运行了一个持续数周的行动,制造了一个虚假的抵押品资产,并通过误导性的签名请求获得了治理访问权;治理接管,快速连续地提交了两笔预先签名的持久 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,接着通过proposalApprove和vaultTransactionExecute,最终调用UpdateAdmin将管理控制权转移到攻击者控制的地址。 -
阶段 3(资金提取):获得完全管理员权限后,攻击者创建了一个
CVT的抵押品市场,切换到攻击者控制的预言机以抬高其账面价格,并提高了或取消了主要资产市场的提款限制。随后,攻击者向协议存入了大量估值过高的CVT,并在大约 12 分钟内执行了 31 次快速提款,提取了USDC、JLP、SOL、cbBTC、USDT、wETH、dSOL、WBTC、JTO和FARTCOIN,总损失约 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 token 作为奖励。奖励以 USDT 计价计算,然后根据协议存储的 LML/USDT 价格转换为 LML 金额后再进行分配。存储的价格通过 updatePrice() 刷新,该函数读取 AMM 现货价格,但强制执行 3600 秒的冷却时间 才能更新。奖励认领通过 APower 的 receive() 根据 msg.sender 触发,因此只有原始质押地址才能认领自己的奖励。
漏洞分析
质押合约(0xbe9713...adce19)中的核心缺陷在于奖励累积和奖励赎回锚定在同一池子的两种不同价格上,且没有任何一致性检查。奖励公式 reward += (10^18 * base_reward) / stored_price 从 _prices[] 计算 LML 支付,这是一个协议存储的 LML/USDT 价格,仅在 3600 秒冷却后通过 updatePrice() 刷新,但支付的 LML 可立即在实时 AMM 现货价格下赎回。任何移动现货价格的外部活动(在此冷却窗口内)会在冻结的累积价格和实时卖出价格之间打开一个缺口,而合约中没有任何内容会拒绝在缺口变得不合理时的认领。



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


攻击分析
以下分析基于交易 0x805d...5b47, 0x70f7...3572。
-
步骤 1:攻击者通过 Moolah 的闪电贷聚合了大量
USDT和WBNB(使用WBNB作为抵押品),并从 Moolah Pool 借款,以及通过 PancakeSwap V4、多个 V3 池和 V2 池进行闪电贷。这些资本是操纵LML/USDT对价格所必需的。 -
步骤 2:攻击者在
LMLtoken 合约上调用swapAndTrans(),将合约中累积的LML费用兑换成USDT。这耗尽了LML合约自身的LML余额,意味着它不再能作为本地 token 来源,任何后续的奖励分配都需要从 LP 对通过swapBack()拉取LML。

- 步骤 3:攻击者通过 PancakeRouter
swapExactTokensForTokensSupportingFeeOnTransferTokens将USDT兑换成LML,接收者设置为死亡地址。购买的LMLtoken 被烧毁,而不是由攻击者接收。唯一目的是消耗掉池子的LML并抬高 AMM 上的LML价格,攻击者并不需要这些 token,只需要价格扭曲。

- 步骤 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,365e18CES,并将资金分配给 5 个辅助合约。每个辅助合约首先收到6,426e18CES,然后调用deposit(12)。在此过程中,每个辅助合约首先查询getPriceForLevel(12),然后根据当前价格准备本次存款所需的CES金额。


- 步骤 2:在所有 5 个辅助合约完成第一轮
deposit后,攻击者将300,000 CES倾销到DEX上,将bank使用的价格从1.067585推低至0.688542。然后,5 个辅助合约逐一执行withdraw,将先前以高价创建的份额以现在较低的价格兑换成CES。每个辅助合约收到9,427e18CES。

-
步骤 3:完成第一轮
withdraw后,攻击者将获得的对手资产兑换回CES,再次推高价格。然后攻击者重复步骤 2-3。 -
步骤 4:最后,在经过多次攻击循环,并偿还了闪电贷以及
166.097975017841805126 CES的闪电费后,攻击者剩余567,736e18CES作为利润。
结论
此事件的根本原因是 Tactile 在存款和提款时都根据一个可操纵的现货价格进行结算,而没有将记账份额锚定在存款时的资产金额或价格上,使得其内部记账完全暴露于入场和出场之间的价格变动。
发行基于波动性资产的份额类头寸的协议,应将每个份额锚定在铸造时的具体资产金额或价格上,以便赎回时能复制原始经济价值,而不是根据实时预言机重新定价。在结算函数必须引用当前价格时,应使用经时间加权或抗操纵的其他来源,并避免在与结算调用同一笔交易中执行的交易所移动的现货价格。
7. SAS Token 事件
摘要
2026 年 4 月 2 日,BNB Chain 上的 SAS token 被利用,损失约 12,000 美元。根本原因在于 token 的自定义转账逻辑存在缺陷:将 SAS 发送到 LP 池只会增加一个全局 sellBurn 计数器,随后任何普通转账都可以直接从池中烧毁 SAS 并调用 sync() 来重写其储备金,而无需经过 AMM 的兑换逻辑。攻击者利用这一点,通过卖出累积 sellBurn,触发一次无关的普通转账从池中烧毁 SAS 并将其储备金推至 1 wei,然后反向兑换剩余的 SAS 以获利。
背景
SAS 是 BNB Chain 上的一种通缩 token,其自定义转账逻辑构建在 PancakeSwap V2 池之上。其 transfer() 函数区分两种路径:卖出路径,在转账目的地是 LP 池时触发,该路径会按转账金额增加一个全局 sellBurn 累加器;普通转账路径,当 sellBurn 非零时,直接从 LP 池中烧毁 SAS,然后调用 sync() 来更新其储备金以匹配当前链上余额。这两种路径旨在协同工作,作为一种通缩机制,响应累积的卖出压力来减少池子的 SAS 储备。
漏洞分析
SAS token 合约(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()检查,因为 token 合约要求transfer()的来源是白名单地址或 EOA。


- 步骤 4:攻击者将
SAS转账到池子,触发了卖出路径并累积了sellBurn。

- 步骤 5:攻击者部署了第二个合约,并在其
constructor()中再次触发了一个普通转账。由于sellBurn已经由于步骤 4 而非零,此转账触发了_burnFromPair()函数,该函数直接从 LP 池中烧毁了SAS,然后调用sync()函数,将SAS储备金减少到 1 wei。

- 步骤 6:攻击者执行了反向兑换,并将剩余的
SAS卖出以获利。
结论
此事件的根本原因在于 SAS token 自定义转账逻辑中的一个缺陷:普通转账可以直接从 LP 池中烧毁 SAS 并将其储备金同步到减少后的余额,从而将累积的卖出活动转化为对池子 SAS 储备金的任意减少,并从中产生巨大的价格扭曲,然后可以通过一次普通兑换来收割。
Token 不应干预外部 AMM 池并绕过正常兑换路径来改变其储备金。如果通缩设计确实需要从池中烧毁,那么烧毁及其伴随的 sync() 必须绑定到一个严格控制的内部触发器,例如受信任的 keeper 或限时计划,而不是搭便车于任意用户转账。
8. Unknown-EIP-7702 事件
摘要
2026 年 4 月 3 日,BNB Chain 上一个启用了 EIP-7702 委托代码的用户账户被盗取了约 17,200 美元。委托的代码暴露了一个 pancakeV3SwapCallback() 函数,但没有适当的访问控制。攻击者直接调用了这个回调函数,并携带了精心制作的 calldata,迫使受害者账户将其 token 转账到一个攻击者控制的地址。
背景
受害者 EOA 使用了 EIP-7702 Type-4 交易来设置委托代码,以便账户能够执行与兑换相关的逻辑。然而,委托的实现包含一个公共的 pancakeV3SwapCallback() 函数,该函数原本只应在合法的 PancakeSwap V3 池回调期间调用。
漏洞分析
根本原因在于委托合约(0x02C809...aEDbAE)的 pancakeV3SwapCallback() 函数中缺少访问控制。
在正确的 UniswapV3/PancakeV3 回调设计中,回调必须验证 msg.sender 是否是预期的规范池(由工厂 + token 对 + 费用得出,或与受信任的池列表进行验证)。在此情况下,该验证缺失,因此任何外部调用者都可以直接调用回调。
由于回调执行该账户托管的 token 转账,缺失的 msg.sender 检查意味着任何携带正数 amount0Delta/amount1Delta 的外部调用都会进入回调内的付款路径,并从受害者账户中转移 token,而实际上并没有发生兑换。
攻击分析
以下分析基于交易 0x5b2c...4261。
- 步骤 1:攻击者直接调用
pancakeV3SwapCallback()并携带精心制作的参数,触发了回调转账逻辑,将受害者的 token 转移到攻击者控制的地址。


结论
此事件是由于在没有严格回调身份验证的情况下,将兑换回调逻辑部署到 EIP-7702 账户所致。由于 pancakeV3SwapCallback() 缺乏访问控制,任何外部调用者都可以调用该回调,并用它来从受害者账户中转移 token,而无需发生合法的兑换。
对于任何实现 V3 类型回调的合约或委托的 EIP-7702 代码,开发人员必须在回调进入任何转账逻辑之前,验证 msg.sender 是否是规范的 PancakeV3 池(由受信任的工厂、token 对和费用等级得出)。
9. Silo Finance 事件
摘要
2026 年 4 月 3 日,Silo Finance 在 Arbitrum 上的 soUSDC 资金库被利用,损失约 359,000 美元。根本原因在于三个缺陷的融合:一个固定的 wstUSR 预言机,在其市场价格已跌至约 0.12 后仍将其价格定在约 1.133;soUSDC 的供应上限机制只限制了资金库自身的存款,但不限制外部存款;以及 totalAssets() 的记账缺陷,它计算了外部存入的 bUSDC 份额,而没有铸造相应的 soUSDC 份额。通过将 USDC 直接存入零上限的 wstUSR 市场(receiver=soUSDC),攻击者抬高了资金库的份额价格,以过高估值的 wstUSR 抵押品借回相同的 USDC,并以抬高的估值赎回了先前获得的 soUSDC 份额,差额从提款队列中的其他健康市场中提取。
背景
Silo Finance 是 Arbitrum 上的一个风险隔离借贷协议。每个 Silo 市场都是一个双向借贷对(例如,wstUSR/USDC):借款人存入抵押品(wstUSR)并借入借贷资产(USDC),而贷方存入 USDC 并赚取利息。当贷方将 USDC 存入特定市场时,他们会收到该市场的存款份额 token。当借款人存入抵押品时,他们会收到抵押品份额 token(例如,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 供 Feed 只跟踪 wstUSR/stUSR 汇率(约 1.133),协议隐含假设 1 stUSR = 1 美元,因此预言机继续将 wstUSR 定价为约 1.133,与市场现实存在约 10 倍的差距。
漏洞分析
wstUSR/USDC 市场的预言机地址在 SiloConfig 中是硬编码且不可变的,无法替换。预言机合约(0x836a1a...04425e)本身是一个 ChainlinkV3Oracle,其底层的 Chainlink Feed(描述:“wstUSR / stUSR 汇率”)只跟踪 wstUSR 到 stUSR 的包装比率(约 1.133),而不是二级市场价格。协议隐含假设 1 stUSR = 1 美元,因此将 wstUSR 定价为约 1.133,而公开市场价格跌至约 0.12,约 10 倍的估值过高。


协议部分意识到风险:soUSDC 对 wstUSR 市场的供应上限设置为 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,797wstUSR定价为约 15,633(每个 1.133),尽管攻击者仅支付了约 1,656。

- 步骤 3:将约 4,222,007
USDC存入soUSDC资金库,获得soUSDC份额(约占总供应量的 91.5%)。资金库将其路由到现有的健康市场(不是wstUSR市场,因为上限=0)。这些soUSDC份额是步骤 6 中提取利润的工具——攻击者拥有的份额越多,当份额价格被抬高时,他们获得的利益就越大。

- 步骤 4:通过
wstUSR_Market.deposit(receiver=soUSDC)将约 14,344USDC直接存入wstUSR市场,并将bUSDC-149铸造给soUSDC。生成的bUSDC份额被记入soUSDC的地址,而不是攻击者的地址。这是核心操纵:soUSDC的totalAssets()现在包括这些bUSDC份额(面值约 14,344USDC),但没有新的soUSDC份额被铸造,因为资金库自身的存款逻辑从未被调用——totalAssets增加,totalShares保持不变,soUSDC份额价格被抬高。同时,这在先前空无一人的wstUSR市场中创造了USDC流动性,这是下一步所必需的。

- 步骤 5:使用步骤 2 中存入的抵押品,从
wstUSR市场借入约 14,344USDC。预言机将抵押品定价为约 15,633,因此在 92% 的最大 LTV 下,攻击者可以借入约 14,344。这收回了步骤 4 中捐赠的USDC——借款和捐赠在现金方面是中性的。但是wstUSR市场现在已经完全耗尽:所有USDC都已被借出,只留下由几乎毫无价值的wstUSR抵押品支持的未偿还贷款。soUSDC仍以面值持有bUSDC份额在totalAssets()中。

- 步骤 6:赎回步骤 3 中获得的所有
soUSDC份额。由于步骤 4 的捐赠,份额价格现在被抬高,因此攻击者收到了约 4,235,143USDC,比步骤 3 存入的 4,222,007 多约 13,136。资金库试图从wstUSR市场提取,但发现没有流动性(在步骤 5 中被借出),因此它从提款队列中的其他健康市场中提取了差额。这就是损失发生的地方:来自其他soUSDC存款者市场的真实USDC被转移以弥补被抬高的赎回。



- 步骤 7:偿还闪电贷。
经过 32 次循环后,soUSDC 仍然持有 wstUSR 市场中的 bUSDC 头寸,这些头寸的面值为约 359,000 美元,但由价值不到该数值一小部分的 wstUSR 抵押品支持——利用率为 100%,基本上是不可追回的坏账,由剩余的 soUSDC 存款者承担。
结论
此事件是由于跟踪质押汇率而非脱锚资产市场价格的预言机、totalAssets() 计算外部计入头寸但未铸造相应份额的资金库记账系统,以及只限制资金库自身存款而不限制外部存款的供应上限机制的结合所致。SiloConfig 中预言机地址的不可变性阻止了在问题显现后进行任何紧急修复。
跨借贷市场聚合的资金库协议应确保 totalAssets() 只计算资金库通过自身存款操作进入的头寸,而不是外部计入的份额余额。预言机地址不应是永久不可变的;当底层资产脱锚时,应存在紧急治理机制来更新价格 Feed。
关于 BlockSec
BlockSec 是一个全栈区块链安全和加密合规提供商。我们构建产品和服务,帮助客户在协议和平台的整个生命周期中进行代码审计(包括智能合约、区块链和钱包)、实时拦截攻击、分析事件、追踪非法资金,并满足 AML/CFT 义务。
BlockSec 已在顶级会议上发表了多篇区块链安全论文,报告了多个 DeFi 应用的零日攻击,阻止了多次黑客攻击并挽救了超过 2000 万美元,并保护了数十亿美元的加密货币。
-
官方 Twitter 账号:https://twitter.com/BlockSecTeam



