On 1 November 2026, an attacker emptied six Premia v3 underwriter vaults on Arbitrum in two transactions sent one second apart. The vaults lost 3.644 WBTC, 43.47 WETH, 48,479 USDC.e and 46,215 ARB, which The Defiant valued at about $437,000. Blockaid flagged the attack while it was still running and described the method in one sentence: the attacker created empty option pools, flash-loaned capital, bought options so that vault collateral was locked into those pools, and then withdrew that collateral as liquidity.
No key was stolen and no oracle was bent. The vaults did what their code allowed: they underwrote options in markets that the attacker had created a minute earlier. This post walks through what Premia’s vaults do, what the chain shows, what is still unknown, and what builders and auditors of options and structured-product vaults should take from it.
Premia v3 splits options trading into two layers. Pools are per-series markets: one pool per base/quote pair, strike, maturity and call/put flag, deployed through a factory. Anyone can create a new series. Underwriter vaults sit above the pools. Depositors put a single asset into a vault, and the vault uses it as collateral to sell (write) options to buyers, collecting premiums in return. A call vault holds the base asset (WBTC, WETH or ARB); a put vault holds USDC.e.
When a buyer trades with a vault, the vault writes options into the matching pool. Writing an option means locking collateral in that pool so the buyer can be paid if the option ends in the money. That collateral leaves the vault’s balance sheet and sits in the pool until the series settles.
This design is common. It is also exactly where an attacker would look first: the vault holds real deposits, and it will move them into a pool contract on request, provided the trade passes the vault’s checks. If those checks treat every factory-deployed pool as a legitimate market, the security of depositors’ money depends on how a brand-new, empty pool behaves.
We read the blocks and receipts directly from a public Arbitrum node. The sequence is short.
0xbeBa8CEfD0D75d747C5AD966Dc17C0Bb60D84dBd called its contract 0x577168C8c6fA937495C3D6961f1d7D734b2d785f (transaction 0xe3c263fc...31f5). Reporting relayed by KuCoin News says this transaction created the six option-pool contracts used later.0x64602cbb...41ac). The attack contract borrowed tokens from the Balancer Vault, including 0.9 WBTC, 11 WETH and 6,000 USDC.e. Option tokens with names such as WBTC-USDC-06NOV2026-78000-C and WETH-USDC-06NOV2026-2200-P were minted and burned, collateral moved from the vaults into the new pools and then on to the attack contract, and Balancer was repaid.0xd7e8086d...44ff). Same sender, same contract, same selector. This one borrowed 12,000 ARB and 9,500 USDC.e and repeated the pattern against the ARB vaults.Both drain transactions succeeded, and each produced close to 400 log entries. Summing only the ERC-20 transfers into and out of the six vault addresses across both transactions gives these net outflows:
| Vault | Asset | Net outflow |
|---|---|---|
| WBTC call | WBTC | 3.644104 |
| WETH call | WETH | 43.472546 |
| ARB call | ARB | 46,215.428616 |
| WBTC put | USDC.e | 20,215.067131 |
| WETH put | USDC.e | 21,333.613826 |
| ARB put | USDC.e | 6,930.677768 |
The three put vaults together lost 48,479.36 USDC.e, which matches The Defiant’s figure exactly. After the attack, the WBTC call vault held about 0.00087 WBTC and the put vaults between about 45 and 126 USDC.e. By TVL, that is most of what Premia v3 had on Arbitrum: DefiLlama showed roughly $533K just before the attack.
The flash loans were only working capital. They were repaid inside the same transactions. The profit came entirely from depositor collateral.
Coindaro also found ten smaller outflows from the same vaults over the next two hours, worth about $16K in total, from other addresses. Who sent them is not known; they may be copycats, the same actor or a rescue effort. They are not included in the figures above.
Premia has not published a post-mortem, so the precise vulnerable function is not confirmed. What is public is enough to describe the shape of the bug.
The key ingredients are:
In other words, the vault’s assumption was “a pool deployed by our factory is a safe place for our collateral”. That only holds if every state a pool can be in, including empty, first-trade and single-participant states, keeps the vault’s collateral attributed to the vault. An empty pool is the most extreme edge case there is: the attacker is the only other counterparty, sets the opening conditions, and can sequence every step inside one transaction.
The snippet below is a simplified, hypothetical illustration of that trust pattern. It is not Premia’s code.
// SIMPLIFIED ILLUSTRATION - not Premia's actual implementation
function trade(PoolKey calldata key, uint256 size, uint256 maxPremium) external {
// Any pool the factory can derive is treated as a valid market
address pool = factory.getPoolAddress(key);
require(pool != address(0), "no pool");
require(_isValidListing(key), "bad strike or maturity");
uint256 premium = _quote(key, size);
require(premium <= maxPremium, "slippage");
asset.safeTransferFrom(msg.sender, address(this), premium);
// Vault collateral leaves the vault and is locked in the pool
uint256 collateral = _collateralFor(key, size);
asset.approve(pool, collateral);
IPool(pool).writeFrom(address(this), msg.sender, size);
// From here on, the vault relies entirely on the pool's accounting
// to keep that collateral attributed to the vault.
}
Nothing in this sketch is obviously wrong in isolation. Strike and maturity are checked, the premium has a slippage bound, and the pool is a genuine factory deployment. The problem is the last comment. If pool-side accounting can be steered by whoever created the pool, especially when the pool has no other liquidity, a vault-level check that only asks “is this a real pool?” offers no protection.
The Premia case joins a long list of exploits where the first moments of a contract’s life were the weak point. Empty ERC-4626 vaults are vulnerable to share inflation. Fresh lending markets have been drained through rounding on the first deposit. And a flash loan let an attacker dictate a thin pool’s spot price for one transaction in the KolanHook exploit.
Empty markets are dangerous for three reasons:
There is also an operational angle. Premia’s team now builds Kyan, its newer platform, but the v3 contracts were still live and still held deposits. As we saw last week with the Troves legacy rebalancer, code a team has stopped watching keeps running for as long as it holds funds.
1. Allowlist the markets a vault may underwrite. Composability is great for traders and dangerous for pooled collateral. A vault that holds depositors’ assets should only write into pools that governance or a curator has approved, or at minimum into pools that meet liquidity, age and parameter requirements. “Deployed by our factory” is not a risk check.
2. Treat pool creation as an attacker capability. In threat models for permissionless factories, assume the attacker deploys the pool, chooses its parameters and is the only counterparty. Every function a vault calls on a pool should be reviewed under that assumption.
3. Verify collateral attribution end to end. After a vault writes into a pool, write invariant tests that check the vault’s claim on that collateral cannot fall unless an option is exercised against it. Fuzz the sequences create pool, trade, add or remove liquidity, settle, all from one actor and inside one transaction.
4. Cap per-market and per-block exposure. Six vaults lost almost everything within one second. Limits on how much collateral can enter a single new series, or how much a vault can underwrite per block, would have bounded the damage even with the underlying bug present.
5. Sunset old deployments deliberately. When a protocol moves to a new version, either wind down the old vaults, pause new underwriting, or keep monitoring and bug-bounty coverage in place. Our smart contract security checklist covers the monitoring side of this.
6. Monitor for the pattern, not just the loss. A single address creating several pools and then trading against vaults in the next minute is an unusual sequence. Alerts on new-series creation followed by large vault trades can buy time for a pause.
| Item | Value |
|---|---|
| Attacker address (tx sender) | 0xbeBa8CEfD0D75d747C5AD966Dc17C0Bb60D84dBd |
| Attack contract | 0x577168C8c6fA937495C3D6961f1d7D734b2d785f |
| Setup tx (block 520,166,285) | 0xe3c263fcae544954367998e48e13112875cfd38a3b9a240e7818bb96313831f5 |
| Drain tx 1 (block 520,166,479) | 0x64602cbbeba5d3c7a5e2cff4f98cc118886fc6051c56fa50458abec2c90441ac |
| Drain tx 2 (block 520,166,483) | 0xd7e8086df0570c5389ca27eb9bcdff290e810c094155b410a42e5bad2b3244ff |
| WBTC call vault | 0x45dF5EA836A15B561937Ae8373ab9eE984aea531 |
| WETH call vault | 0xbae43c546DFADC69576aE73C68e0694A54F08e1B |
| ARB call vault | 0xDC631d88dbB5eb39f5c4Bf8B4e5298d098912fFf |
| WBTC put vault | 0x6A1FC0E1c60BA6564CDe4910A425F1F1a1d18C1F |
| WETH put vault | 0xD46993F25D298ebbCD31E941156C66f7e628A52a |
| ARB put vault | 0xBe3E229319f86f5ee96ee1dc0b6d55e8b68a439e |
The Premia exploit did not need a price oracle, a stolen key or a novel cryptographic trick. It needed a vault that would put real collateral into a market nobody else had ever used. If your protocol lets anyone create markets and lets pooled capital flow into them, the empty-market case is your threat model, not an edge case. If you are building vaults, options or any permissionless market factory, talk to our team or see our audit pricing to have those trust boundaries reviewed before an attacker reviews them for you.
How a replaced rebalancing contract that kept its permissions let an attacker drain about 8.57 WBTC from the Troves xWBTC/WBTC vault on Starknet.
How 50 signed EIP-7702 authorizations turned a Binance hot wallet into an attacker's sweeper in a $6.3B theft, and what builders should learn.
How a never-cleared transient hash and a caller-chosen call target let an attacker forge a zkLink Nova batch root and drain about $780K on Ethereum.
How a UTC day rollover booked a scheduled principal payment as received, reopened draw capacity and let an attacker drain 1.013M USDC on Avalanche.