October 20, 2026
|
Exploit Postmortem
Cover image for "Enso Finance's $14.6K Loss and How Olympix Would Have Prevented It"

Enso Finance's $14.6K Loss and How Olympix Would Have Prevented It

Date: September 8, 2026

Chain: Ethereum

Loss: about 5.6 ETH, roughly $14.6K

Class: oracle that reused a pool's fee setting as its time window, producing a near-spot price

On September 8, 2026, an attacker swapped 0.683 WETH for 268.42 FARM tokens on Uniswap V2 and deposited them into Enso Finance's legacy DPI Strategy Vault. The vault's oracle looked at those FARM tokens and valued them at about 6.3 WETH, roughly 9.2 times what the attacker had just paid.

The vault minted shares to match the 6.3 WETH figure, and the attacker redeemed them for a basket of the vault's real holdings, netting about 5.6 ETH, worth around $14,560. The oracle was supposed to average the price over a window of time, and that window was set with the wrong number, the pool's fee tier, so the "average" came out close to the live spot price of a lopsided pool.

A Strategy Vault From Enso's First Chapter

In December 2021, Enso, a platform where users built and shared custom indices and DeFi strategies, announced a plan to draw liquidity away from six index protocols, including Index Coop. The DPI Strategy Vault came out of that era. A strategy vault holds a basket of tokens, takes deposits, and issues shares, and to issue the right number of shares it has to know what each deposit is worth in ETH. In Enso's design that job fell to an oracle used by the vault's Controller contract when a deposit came in.

After the incident, the team said on X, as reported by KuCoin, that the affected contracts had been deprecated over four years ago, that users had been advised to withdraw through official channels such as Discord, Twitter and GitHub, and that Enso's current infrastructure doesn't use these contracts. The vault still held funds, and its contracts were still callable.

The Fee Tier in the Time Slot

Uniswap V3 pools each have a fee tier, stored as a plain integer: 500 for a 0.05% pool, 3000 for 0.3%, 10000 for 1%. Uniswap V3 also offers a time-weighted average price, or TWAP, which averages the pool's price over a number of seconds the caller chooses through an argument called secondsAgo. A longer window makes the price hard to push around, because an attacker would have to hold a distorted price for that whole stretch of time.

According to SlowMist's alert, Enso's oracle took the fee tier value from its pool registry and passed it in as secondsAgo. Both are small integers, so nothing in the code objected. The window the oracle actually used was therefore whatever number described the pool's fee, which left it near enough to spot that it reflected the pool's current state, and KuCoin's summary of the SlowMist finding describes price estimates that resembled immediate market quotes and lacked TWAP consistency checks and price range validation. The DeFiHackLabs reproduction, built from the transaction trace, sees the same thing from the outside: the oracle called the V3 pool's observe() function with short TWAP windows that varied from pool to pool, instead of one fixed, safely long window.

The single idea worth taking away is that a number's meaning travels with it, and the type system won't carry that meaning for you. A fee expressed in hundredths of a basis point and a duration in seconds can both be uint values, and swapping one for the other compiles cleanly. It's like a recipe where the oven temperature got typed into the timer, and the dish still goes in the oven, just for the wrong amount of time.

How 0.683 WETH Became 6.3

The short window only mattered because the pool behind it was already off. The Uniswap V3 pool the oracle read for FARM was imbalanced, so its near-spot price sat far from what FARM traded for elsewhere. Together, the two flaws meant the oracle would value FARM at far more than it was worth on the open market.

The whole attack ran in one transaction, sent from the wallet 0x3196...b73A, which deployed a contract that did the work as it was being created. That contract bought 268.42 FARM for 0.683 WETH from the Uniswap V2 FARM/WETH pair, where FARM was correctly priced, and deposited it into the strategy through the Controller's deposit() function, which anyone could call. The vault mints shares on the change in the strategy's estimated value, so when the oracle priced the FARM off the imbalanced V3 pool at about 6.3 WETH, the vault minted shares as if that much value had arrived.

The contract then called withdrawWETH() on the Controller, which burned the inflated shares and, through Enso's GenericRouter, sent out a slice of the strategy's real holdings in UNI, AAVE and MKR. Per the DeFiHackLabs reproduction and crypto.training's, those tokens were worth about 5.6 ETH more than the 0.683 WETH spent on FARM.

How Olympix Traces a Value Into the Wrong Role

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and takes in the surrounding context, including how the protocols it calls expect to be called, to infer invariants the system depends on but never writes down. In Enso's vault, the state that matters is the number of shares in circulation against the vault's assets, and Controller.deposit() is the entry point that changes it based on an oracle price.

The engine maps every path into deposit and uses signals to pick which ones to attack. The signal here is a parameter type and units mismatch feeding a price read: a value that comes from pool fee metadata flows into the secondsAgo argument of a TWAP call, so the "time-weighted" price is effectively spot. That defect is visible in the oracle code itself, and Olympix's static analysis surfaces it. Olympix has flagged this class before in other codebases, where liquidity and share calculations read a price an attacker could move.

Enso's vault depends on a rule it never states: the value it credits for a deposit has to stay in line with what the deposited tokens are actually worth, so the shares it mints never claim more than the deposit brought in. That's the rule BugPoCer goes after. Counterexample-Guided Invariant Refutation begins with what the strategy as a whole owes its existing shareholders and works outward to the deposits that could shortchange them, so here it varies which basket token comes in, at what price it was bought, and how the oracle's pool reads at that moment, until a deposit mints more value than it adds. An item whose pricing pool is out of line with the wider market, read through a window too short to smooth it out, gets there in a single deposit.

The counterexample comes back as the concrete sequence (buy FARM cheaply, deposit, withdraw), the minimal conditions that trigger it, and a generated Forge test that replays it. That's the September 8 attack produced in development instead of on mainnet, and because the engine runs during development, at every merge and before release, the mismatch would have shown up the day the oracle code was written.

A Deprecated Vault Still Holding Funds

Enso had told users to withdraw, and its current infrastructure doesn't touch these contracts, yet the vault still held enough for an attacker to take 5.6 ETH. A wrong argument in an oracle call can sit quietly through every honest deposit and only matter once a pool drifts out of balance, which is exactly when a tool that checks what each value means, and then tries to break the result, earns its place next to an audit. To see what Olympix finds in your own price paths, book a technical walkthrough.

On-Chain References

Protocol: Enso Finance (legacy DPI Strategy Vault)

Chain: Ethereum

Date: September 8, 2026, 19:46:59 UTC

Loss: about 5.6 ETH (about $14,560)

Attacker EOA: 0x3196...b73A

Strategy (vault) proxy: 0x890e...5942

StrategyController proxy: 0x173c...EbE8

EnsoOracle: 0xAb75...7DC0

Enso GenericRouter: 0x9048...4a52

Uniswap V2 FARM/WETH pair: 0x56fe...1A58

Uniswap V2 swap: 0.683 WETH in, 268.42 FARM out

Oracle valuation of the deposit: about 6.3 WETH (about 9.2x)

Exploit tx: 0x63fb...1ad3

Block: 25934827

Sources

SlowMist: Enso Finance DPI Strategy Vault exploit alert

KuCoin News: Enso Finance Vault Loses 5.6 ETH Due to Oracle Price Error

DeFiHackLabs: EnsoFinance short-window Uniswap V3 TWAP oracle PoC

crypto.training: Reproduced Exploits, Enso Finance strategy vault

Crypto Briefing: Enso Finance Sets Up Vampire Attack for Six Protocols

More from Olympix:

No items found.

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