October 20, 2026
|
Exploit Postmortem
Cover image for "Kolan Protocol's $3.3K Loss and How Olympix Would Have Prevented It"

Kolan Protocol's $3.3K Loss and How Olympix Would Have Prevented It

Date: October 15, 2026

Chain: Ethereum

Loss: about 1.28 ETH, roughly $3,300

Class: permissionless settlement that places liquidity at a spot price the caller can move

Kolan Protocol sold a kind of insurance on token purchases. A buyer of its KLN token could pay a premium to open a window, and until that window closed the purchase could be undone and the ETH spent on the tokens would come back. By October 15, 2026, two of those windows had been expired for days, one holding 2.05 ETH that ran out on October 8 and one holding about 0.26 ETH that ran out on October 10, and at 11:06 UTC an attacker settled both of them inside a single transaction built around them.

The attacker flash-borrowed 6.7 WETH, pushed KLN's price in the pool, and then called KolanHook.accept() on the two expired windows, which anyone is allowed to do after expiry. Settling them made the hook put the windows' escrowed ETH back into the pool as liquidity at the price the attacker had just set, and the attacker sold into that fresh liquidity, emptied the hook's 2.31 ETH and walked away with about 1.28 ETH, roughly $3,300, according to ExVul's alert.

Insurance Built Into a Uniswap v4 Hook

Kolan runs through a Uniswap v4 hook called KolanHook, attached to an ordinary v4 pool of native ETH against KLN. A hook is a contract that Uniswap v4 calls at set points around a pool's activity, so it can add its own rules to swaps and liquidity. According to Kolan's public repository, a window lasts 6 hours per 0.05 ETH of premium, with a minimum of 30 minutes and a maximum of 7 days, the premium is capped at 30% of the ETH the purchase spends, and these parameters are immutables of the hook that no function can change. The hook also charges a 1% tax on the ETH side of every swap.

A window ends in one of two ways. The owner can cancel before expiry, which returns the ETH spent on tokens and sends the tokens back into the pool. Or the window is accepted, which sends the tokens to the owner and puts the escrowed ETH into the pool. On accept, if the price has moved past the window's gap, the ETH fills that gap, leaving the pool as it would be after a plain buy, and otherwise it's placed over the same width just below the current price, as support for sellers.

Settlement Anyone Can Trigger, at a Price Anyone Can Move

The repository states that the owner can call accept(id) at any time, and that after expiry anyone can, and the verified source matches: the only guard reverts when the caller isn't the owner and the window hasn't expired yet. That makes sense as a convenience, since a window that nobody settles would leave ETH and tokens stuck. The second ingredient sits inside the hook's _closeWindow() routine. According to the DeFiHackLabs analysis of the verified code, it reads the pool's live sqrtPrice from the PoolManager, the price left by whatever swap ran last, uses it to decide whether the window is still in place, and when it isn't, adds the escrowed ETH as one-sided liquidity around that price and runs a buy-back swap with no price limit at all. There's no time-weighted average, no deviation check and no slippage bound anywhere in that path.

Each choice is reasonable on its own, and together they let a stranger decide both when a window settles and what price it settles at, inside a transaction where that stranger also controls the trades before and after. Any function a stranger can call has to be safe under every state that same stranger can set up first, and a spot price within one transaction is state the caller sets up. A cashier who lets any customer close out someone else's layaway at whatever price is on the shelf tag, while the customer holds the label gun, is running the same settlement.

Two Expired Windows, One Transaction

The attacker's wallet, 0x8df7...e382, sent one transaction in block 26197504 at 11:06:11 UTC that deployed two helper contracts and ran the whole attack from them. The helper borrowed 6.7 WETH from the Balancer Vault at no fee, unwrapped it, and swapped the 6.7 ETH into KLN through the pool to move its spot price. With the price where it wanted, it called accept() on window 10 and window 42, neither of which it owned, and because both had expired, nothing stopped it. The KLN from those windows went to their owners as designed, and window 42, now out of place at the moved price, had its escrowed ETH placed into the pool around the manipulated price.

The helper then swapped its whole KLN balance back to ETH through that freshly placed liquidity, taking out 7.979914429958618589 ETH, re-wrapped 6.7 WETH to repay Balancer, and sent the remaining 1.279914429958618589 ETH to the attacker's wallet. KolanHook's net outflow in the transaction was 2.309861 ETH, its entire balance, with about 1.03 ETH of that staying in the pool. After 0.00046 ETH of gas, the attacker cleared 1.279453 ETH.

How Olympix Follows a Public Call Into a Liquidity Move

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, such as a README's description of what accept() is for, to infer the invariants the system depends on. In KolanHook the state that matters is the pool's price and where the hook places escrowed ETH, and the entry point that matters is accept(), which becomes callable by anyone the moment a window expires.

Olympix's static analysis surfaces the signal: a function any caller can reach that triggers a liquidity modification and an unbounded swap, and inside it a read of the pool's instantaneous price with no TWAP or slippage guard before that price decides where funds go. Olympix has flagged this class before in other codebases. From that signal the engine narrows from every path, to the feasible ones, to the ones that reach the invariant, which in plain words is that settling a window shouldn't hand value to whoever happens to settle it.

BugPoCer is built to break a rule like that one. Its Counterexample-Guided Invariant Refutation treats the hook, the pool and an outside trader as one system, and it executes sequences around accept() until a third party ends a transaction holding more ETH than it started with. The sequence that does it is a swap that moves the price, a stranger's accept() on an expired window, and a sell back into the liquidity the hook just placed. BugScout, which starts from the flagged price read and tries known manipulation strategies against it, would be looking at the same function, and symbolic execution supports both. BugPoCer's counterexample is the concrete sequence of state changes, the minimal conditions that trigger it and a generated Forge test that replays it, which is the October 15 transaction produced in development instead of on mainnet. Because Olympix runs automatically in development, at every merge and before release, a convenience path like post-expiry settlement gets tested against an attacker the moment it's written.

Settle Windows on Prices Nobody Can Steer

Kolan's design made every window's worst case predictable for the buyer, and the gap opened at the point where settlement met the live pool. For builders writing hooks that move liquidity on behalf of users, check every public trigger against a caller who controls the price around it. To see how Olympix maps those triggers in your hooks and returns a runnable counterexample wherever a caller can steer the outcome, book a technical walkthrough.

On-Chain References

Protocol: Kolan Protocol (KolanHook, Uniswap v4 hook)

Chain: Ethereum

Date: October 15, 2026, 11:06:11 UTC (block 26197504)

Loss: 2.309861 ETH drained from KolanHook; 1.279914 ETH to the attacker (about $3,300 per ExVul)

KolanHook (victim, verified source): 0x0136...a8eC

Attacker EOA: 0x8df7...e382

Attack helper (flash-loan recipient): 0x4d6a...835f

Attack contract (tx target): 0xEBEa...5F79

Exploit tx: 0x7b13...15a9

KLN token: 0x2CAD...a1bF

Flash loan: 6.7 WETH from the Balancer V2 Vault 0xBA12...F2C8

Sources

ExVul: Kolan Protocol alert on X

DeFiHackLabs: KolanHook_exp.sol proof of concept

c0llback: kolan-contracts repository and README

More from Olympix:

No items found.

Ready to Shift Security Assurance In-House? Talk to Our Security Experts Today.