X100 Exploit: A Flash-Loaned Senate Drained $4.75M

本文为原文前 6,000 字符的节选翻译,完整内容请查看原文。

X100 Exploit: A Flash-Loaned Senate Drained $4.75M

Originally published at panda-security.xyz On 24 October 2026 at 14:11:47 UTC, a single Ethereum transaction turned a flash loan into a governance majority at X100, then used that majority to make the project’s own treasury sell 400,000 X for roughly 36 USDT. The attacker walked away with about 4.75 million USDT from that one transaction.

该文章最初于 2026 年 10 月 24 日 14:11:47 UTC 发布在 panda-security.xyz。一次以太坊交易将一笔闪电贷转化为 X100 的治理多数席位,随后利用该多数席位迫使项目金库以约 36 USDT 的价格出售了 400,000 枚 X 代币。攻击者通过该笔交易卷走了约 475 万 USDT。

Follow-on transactions using the same path pushed the total realized to roughly $4.85M, according to Blockaid. Nothing here required a stolen key or a compiler bug. The governance system did exactly what it was written to do. It just measured voting power at the one moment an attacker could rent it.

据 Blockaid 称,后续使用相同路径的交易将总获利推高至约 485 万美元。此过程中并未涉及私钥被盗或编译器漏洞。治理系统完全按照其编写逻辑运行,只是在攻击者能够租用投票权的瞬间衡量了投票权。

TL;DR Protocol: X100, an ERC-20 token project (ticker X) whose “Senate” decides where the project’s liquidity sits. Chain: Ethereum mainnet. Loss: 361,799.999998 X left the Freezer/DexTreasury in the main transaction; the attacker realized about 4.75M USDT. Blockaid reported about 4.85M USDT and roughly 550,000 X taken across three transactions.

简述:协议为 X100,这是一个 ERC-20 代币项目(代码 X),其“参议院”决定项目流动性的存放位置。链为以太坊主网。损失:在主交易中,361,799.999998 枚 X 代币从 Freezer/DexTreasury 流出;攻击者获利约 475 万 USDT。Blockaid 报告称,在三笔交易中总计损失约 485 万 USDT 和约 550,000 枚 X 代币。

Root cause: anyone could join the Senate instantly for a 100 X fee, seats went to the largest current frozen balances, and proposals could be voted and executed in the same transaction. No snapshot, no stake age, no timelock. Amplifier: the treasury swap accepted minOut = 0 into a pool the attacker had created earlier in the same transaction.

根本原因:任何人只需支付 100 X 的费用即可立即加入参议院,席位分配给当前冻结余额最大的参与者,且提案可以在同一笔交易中完成投票和执行。没有快照机制、质押时长要求或时间锁。放大因素:金库兑换接受 minOut = 0,并进入了攻击者在同一交易中预先创建的流动性池。

How X100 Governance Was Supposed to Work: X100 describes its Senate as the body that controls where protocol liquidity is held, with smart contracts carrying out its decisions. Holders lock (“freeze”) X in a contract called the Freezer, and the three largest frozen positions among Senate applicants hold the three seats.

X100 治理机制的预期运作方式:X100 将其参议院描述为控制协议流动性存放位置的机构,由智能合约执行其决策。持有者将 X 代币锁定(“冻结”)在名为 Freezer 的合约中,参议院申请者中冻结金额最大的前三名持有三个席位。

The Freezer also acts as a treasury, holding X and Uniswap V3 positions, and exposes a v3Swap function that the Senate can direct. Before the attack, per Coindaro’s reading of the Senate’s on-chain ranking events, the seats were held by stakes of 20,500 X, 19,000 X and 1,000 X. In other words, the whole treasury was guarded by roughly 40,500 frozen tokens.

Freezer 同时充当金库,持有 X 代币和 Uniswap V3 头寸,并提供一个可由参议院调用的 v3Swap 函数。根据 Coindaro 对参议院链上排名事件的解读,攻击发生前,三个席位分别由 20,500 X、19,000 X 和 1,000 X 的质押持有。换言之,整个金库仅由约 40,500 枚冻结代币保护。

At a price around $50 per X, that is about $2M of stake protecting many times that amount in treasury assets. That ratio alone should have been a red flag.

按每枚 X 代币约 50 美元的价格计算,这相当于约 200 万美元的质押保护着数倍于此的金库资产。仅此比例就应被视为一个危险信号。

Root Cause: Voting Power Measured in the Present Tense. Three design choices combined into the exploit. Each one shows up regularly in audit findings on its own. 1. Instant, permissionless Senate entry: ExVul’s analysis notes that applyForSenate() let anyone become a candidate immediately for a 100 X fee. There was no waiting period between applying, freezing tokens and taking a seat.

根本原因:以现在时态衡量投票权。三种设计选择共同导致了此次漏洞利用,每一种在审计报告中都屡见不鲜。1. 即时、无需许可的参议院准入:ExVul 的分析指出,applyForSenate() 函数允许任何人支付 100 X 费用后立即成为候选人。申请、冻结代币和获得席位之间没有任何等待期。

  1. Seats ranked by live balances: Seats were assigned from current frozen balances. There was no checkpoint of voting power at an earlier block and no requirement that tokens had been frozen for any length of time. If you could hold enough X for one transaction, you could be a senator for that transaction.

  2. 按实时余额排名席位:席位根据当前的冻结余额分配。没有针对早期区块的投票权快照,也没有要求代币必须冻结一定时长。只要能在单笔交易中持有足够的 X,就能在该交易中成为参议员。

  3. Same-transaction propose, vote and execute: Once two of three seats were captured, a proposal could be created, approved and executed immediately. ExVul reports that proposal #7 auto-counted the proposer’s vote, the second helper voted, and execute() ran straight away. A timelock of even a few hours would have broken the flash loan, since the loan must be repaid in the same transaction.

  4. 同一交易内提案、投票和执行:一旦三个席位中的两个被占领,提案即可立即创建、批准并执行。ExVul 报告称,第 7 号提案自动计入了提案者的投票,第二个辅助账户进行了投票,随后 execute() 函数立即运行。即使是几个小时的时间锁也能破坏闪电贷,因为贷款必须在同一笔交易中偿还。

Attack Walkthrough: The following sequence is assembled from BlockSec Phalcon, ExVul and Coindaro’s on-chain reconstruction. We confirmed the transaction hash, sender, block (26,263,022), timestamp and the victim and coordinator contracts against a public Ethereum node.

攻击流程:以下序列整理自 BlockSec Phalcon、ExVul 和 Coindaro 的链上重构。我们已通过公共以太坊节点确认了交易哈希、发送者、区块(26,263,022)、时间戳以及受害者和协调者合约。

Step 1: Rent the stake: A contract deployed by the attacker wallet in the attack transaction itself borrowed about 1.94M USDT in a flash loan and bought roughly 38,200 X from the main Uniswap V3 X/USDT pool.

第一步:租用质押物:攻击者钱包在攻击交易中部署了一个合约,通过闪电贷借入约 194 万 USDT,并从主要的 Uniswap V3 X/USDT 池中购买了约 38,200 枚 X 代币。

Step 2: Outbid the incumbents by one raw unit: The X was split between two helper contracts. Each paid the 100 X application fee and froze 19,000.000001 X, one millionth of a token more than the 19,000 X incumbent. The two helpers took seats two and three, pushing out the 19,000 X and 1,000 X senators.

第二步:以微小单位超越现有席位:这些 X 代币被分配给两个辅助合约。每个合约支付了 100 X 的申请费,并冻结了 19,000.000001 枚 X,比原有的 19,000 X 持有者多出百万分之一。这两个辅助合约占据了第二和第三席位,挤掉了原有的 19,000 X 和 1,000 X 参议员。

Step 3: Prepare a pool the attacker controls: The attacker created a new PancakeSwap V3 X/USDT pool with a 0.01% fee tier and seeded it with a tiny amount of liquidity. Coindaro reports about 100 USDT on the USDT side. This pool is where the treasury would be forced to sell.

第三步:准备攻击者控制的流动性池:攻击者创建了一个费率为 0.01% 的新 PancakeSwap V3 X/USDT 池,并注入了极少量的流动性。Coindaro 报告称 USDT 一侧约为 100 USDT。该池即为金库被迫进行抛售的目标。

Step 4: Pass and execute the proposal: One helper submitted a proposal calling the Freezer’s v3Swap with 400,000 X in, minimum output 0, routed through the new PancakeSwap pool. The other helper voted, and the proposal executed in the same call. ExVul measured the treasury’s proceeds at 35.675313 USDT for 400,000 X.

第四步:通过并执行提案:一个辅助合约提交了一项提案,调用 Freezer 的 v3Swap 函数,投入 400,000 枚 X,最小输出设为 0,并通过新的 PancakeSwap 池进行路由。另一个辅助合约进行投票,提案在同一调用中执行。ExVul 测得金库出售 400,000 枚 X 的收益仅为 35.675313 USDT。

Step 5: Pull the liquidity and cash out: The attacker withdrew their liquidity from the PancakeSwap pool, which now held the treasury’s X, and sold part of it into the real Uniswap V3 pool.

第五步:撤出流动性并套现:攻击者从 PancakeSwap 池中撤回了流动性(此时池中已持有金库的 X 代币),并将部分代币卖出到真实的 Uniswap V3 池中。