链上合约安全审查 · BNB Smart Chain

一个可以把任何池子瞬间变成 99% 税的 Hook

0x6c94521Ef0Fe5d828Cb201D600AE68Ef6e334bd6 · PancakeSwap Infinity CL Hook

未开源 · 部署于 2026-08-20 · 已挂接 20 个池 · 审查日期 2026-08-21

⛔ 结论:高风险,不应与之交易或向其关联池提供流动性

该 hook 把「这个池收多少手续费」的决定权,完整交给了一个外部账户(EOA)。这个账户可以在任意时刻、对任意挂接了本 hook 的池子,把单笔交易手续费直接改成 99%——没有时间锁、没有更低的上限、没有多签、改完下一笔交易立即生效

这不是理论推演。链上记录显示该账户已经实际把费率设到过 99.00% / 95.84% / 89.20% / 88.88%;在分叉环境中复现,一笔 30,586 gas 的普通交易,就让当前仍在运行的 KII/USDT 池的下一位交易者损失 98.95% 的本金

手续费上限
99%
字节码硬编码 990000/1e6
生效延迟
0 区块
无时间锁,下一笔即生效
分叉复现损失
98.95%
买入与卖出方向均如此
受影响池
18 / 20
动态费池才会被劫持
控制者
1 个 EOA
无多签,所有权不可转移
源码
未开源
仅能从字节码逆向

01合约身份

所有事实均取自 BNB Smart Chain 公开链上数据与公开区块浏览器 API。

项目含义
合约类型PancakeSwap Infinity CL Hook不是 Uniswap V4;挂在 Pancake Infinity 的 CL PoolManager 上
源码验证未开源BscScan / Sourcify / Blockscout 三处均无源码,只能逆向字节码
代码体积2,893 字节极小,编译器 solc 0.8.26
部署方式CREATE2(通用确定性部署器)部署交易发起者与 owner 是同一个 EOA
部署时间2026-08-20 04:00 UTC审查时仅上线约 1 天
owner0x973d1b35…89d3f9普通外部账户,非多签、非合约
可升级性不可升级无代理、无 delegatecall 到外部实现
所有权转移不存在该函数既不能转让也不能放弃——owner 永久锁定为该 EOA
权限位图0x42仅注册 afterInitialize + beforeSwap

为什么「所有权不可转移」在这里是缺点

整段运行时字节码里只有 两条 SSTORE,都写向手续费表,owner 所在的存储槽从不被写入。好处是外人无法夺权;代价是这个 EOA 的私钥一旦泄露或丢失,控制权将永久落在攻击者手里,且团队自己也无法通过「放弃所有权」来向用户证明池子已经安全。

02它是怎么工作的

逆向出的 17 个函数中,只有一个是外部可写入口。

PancakeSwap Infinity 允许池子声明「动态手续费」(fee = 0x800000)。这类池每次交易前都会回调 hook 的 beforeSwap,并采纳 hook 返回的费率覆盖池子原本的设定。本 hook 对这个机制的实现是:

// afterInitialize —— 建池时把该池费率初始化为 0
customFees[poolId] = 0

// beforeSwap —— 每笔交易前,无条件返回表里的值 + 覆盖标志位
return (selector, 0, customFees[poolId] | 0x400000)

// setCustomFeeById —— 唯一的外部写入口
function setCustomFeeById(bytes32 poolId, uint24 fee) {
    require(msg.sender == owner, "Not owner");
    require(fee <= 990000, "Fee too high");   // = 99%
    customFees[poolId] = fee;
}

三个要点决定了风险性质:

⚠️ 关键的第三点,在链上已经发生

目前唯一仍有实际流动性的 KII/USDT 池,并非由 hook 的 owner 创建(建池者是另一个地址),且池中有 15 个不同地址提供过流动性。也就是说,一批第三方的资金,正暴露在一个与他们无关的 EOA 的单方面定价权之下。

03链上行为:99% 不是理论上限

该 hook 自部署以来的全部 72 次费率变更记录,按池分组还原。

USDT / SpaceXcoin USDT / ぬいぬい MCT / USDT USDT / KII(当前唯一有流动性)
阶梯线=该池在每一时刻的实际生效费率(费率一经设定即保持到下次变更)。纵轴为对数刻度以同时容纳 0.01% 与 99%。四个尖峰分别是 89.20%、99.00%、95.84%、88.88%。完整数值见下方表格。

费率变更记录(节选高位事件)

时间 (UTC)设定费率状态
08-20 04:36USDT / SpaceXcoin89.20%极端
08-20 05:01USDT / SpaceXcoin99.00%触顶
08-20 06:13USDT / ぬいぬい95.36%极端
08-20 06:14USDT / ぬいぬい95.84%极端
08-20 06:22USDT / ぬいぬい90.00%至今未改
08-20 07:03MCT / USDT88.88%持续约 4.5 小时
08-20 15:37USDT / KII4.50%当前值

一个重要的事实澄清

在这些高费率窗口内,没有任何一笔交易真正以 ≥5% 的费率成交——623 笔历史成交中,最高档位是 4.53%。也就是说:目前没有证据表明已有用户因此被实际收割。从行为模式看(代币叫 “My Clean Token”、“Liability Vortex”,池子随后被抽空、当前流动性为 0),更像是开发者在主网上测试自己的费率上限

但这不改变风险评级。「能力已经就位、只是还没被使用」与「不具备该能力」是两件完全不同的事——而且其中一个池此刻仍挂着 90% 的费率,任何人现在在那里交易都会立刻损失九成。

04分叉复现:一笔交易,98.95% 的损失

在 BNB Smart Chain 主网分叉环境(Foundry anvil)中,对当前仍在运行的 KII/USDT 池执行完整攻击路径。

1
基线报价

用 PancakeSwap 官方 CLQuoter 报价:1,000 USDT → 14,802.30 KII(当时费率 4.50%)。

2
owner 改费率

以 owner 身份调用 setCustomFeeById(poolId, 990000)。交易成功,消耗 30,586 gas,无需任何前置条件。

3
相同报价再来一次

同样 1,000 USDT,现在只能换到 155.29 KII

方向投入4.50% 档位99% 档位损失
买入 USDT → KII1,000 USDT14,802.30 KII155.29 KII−98.95%
卖出 KII → USDT10,000 KII613.50 USDT6.44 USDT−98.95%

买卖双向对称受损——这意味着它既能吃掉买家的本金,也能把已经持币的人锁在池子里(卖出等于放弃 99%),效果等同于一个可以随时开关的貔貅盘。

05最坏情况下的攻击剧本

这套机制的危险之处在于,它可以被组合成一次原子化的、不依赖价格波动的提取。

A
观察到一笔大额买单进入内存池

BNB Smart Chain 上交易排序可通过 builder 影响,把自己的交易插到受害者之前并不困难。

B
同一区块内先做两件事

① 在当前价位补一笔集中流动性(hook 注册 beforeAddLiquidity,加减流动性完全不受限制);② 把费率设成 99%。

C
受害者的交易执行

按 Infinity 核心逻辑 feeGrowthGlobal += feeAmount × Q128 / liquidity,这 99% 的手续费全额记入当前区间内的 LP 头寸——也就是刚刚补进去的那笔。

D
撤流动性、领手续费、把费率调回 0.5%

整个过程在一个区块内完成,池子价格几乎未动,链上看不出任何异常价差。

相比传统三明治攻击,这个路径不需要推动价格不受滑点保护约束——受害者设置的滑点上限保护的是价格,而这里被拿走的是手续费。用户即便把滑点调到 0.1%,也拦不住这一笔。

06它做不到的事

一份有用的风险评估也需要说清边界。以下几项经字节码与权限位图确认为不成立

常见担忧结论依据
hook 能直接吞掉交易资金吗不能权限位图 0x42 未包含任何 ReturnsDelta 位,hook 无法在结算中截取代币
能阻止 LP 撤出流动性吗不能未注册 before/afterAddLiquidity 与 before/afterRemoveLiquidity,增减流动性不经过 hook
能偷已经存在池外的代币吗不能合约无 transfer/approve 类调用;lockAcquired 仅原样回传数据,无资金动作
能被外人夺取控制权吗不能运行时无任何写 owner 槽的路径
会影响固定费率的池吗不会核心库仅在 fee == 0x800000(动态费)时才采纳 hook 返回值;20 个池中有 2 个是固定费率,不受影响
能升级成别的逻辑吗不能非代理合约,无 delegatecall 到可变实现

换句话说:这个 hook 的全部危险都集中在一处——一个不受约束的费率旋钮。但因为手续费在集中流动性做市中会流向 LP,而 LP 头寸是可以在同一个区块里临时补上的,这一个旋钮已经足以构成完整的资金提取路径。

07结论与建议

如果你是交易者

如果你是流动性提供者 / 项目方

如果要把它做成一个可信的产品

该 hook 的设计意图(可调的动态手续费)本身是合理的,问题全在缺少约束。要达到可用于第三方资金的标准,至少需要: 开源并验证合约; 把上限从 99% 降到一个做市意义上合理的数值(官方同类实现封顶 5%); 费率上调加时间锁,让用户有退出窗口; 把 owner 换成多签; 限制只有建池者本人能设置自己池子的费率,而不是由 hook owner 统管所有池。

在这五项落地之前,无论开发者的实际意图如何,其他人的资金放在这里都是没有保护的。