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

Flamincome's $597K Loss and How Olympix Would Have Prevented It

Date: September 16, 2026

Chain: Ethereum

Loss: about $597K, the 597,352 USDT the strategy lost, of which the attacker kept about $346K after costs

Class: a strategy that counted assets anyone could deposit on its behalf as its own, priced off a depegged pool

At 13:49:59 UTC on September 16, 2026, one Ethereum transaction borrowed about $18 million in USDT from Morpho, routed it through Curve, Yearn, Convex and Balancer, withdrew about 544,260 USDT from Aave, and ended with 345,902.67 USDT in the attacker's wallet. The strategy behind it lost 597,352 USDT, about $597K, and the money came from VaultYUSDT, a vault Flamincome deployed in early 2021 that was still holding real Aave liquidity five years later.

The vault's strategy worked out its own value by reading a Convex reward pool balance that anyone could add to on its behalf, then pricing that balance with a Curve function that ignored a severe depeg. The attacker stuffed the strategy with cheap LP tokens, watched the vault's share price jump, and redeemed shares against the real USDT underneath.

A Yield Vault From 2021 Still Holding Real Money

Flamincome launched in September 2020 as the Ethereum yield arm of the Flamingo Finance ecosystem, incubated by Neo Global Development. It worked like Yearn: users deposited tokens into a vault, received shares, and a strategy contract deployed the deposits into lending and liquidity protocols for yield. VaultYUSDT took USDT, and its strategy held positions in Aave and in a Curve pool staked on Convex.

Etherscan shows the VaultYUSDT contract created in early 2021 and the strategy, a proxy pointing at an implementation contract, a few weeks later. In September 2026, real aUSDT, Aave's interest-bearing USDT, still sat in the strategy, and the vault's share price still depended on how the strategy counted its assets.

Two Mistakes in One Balance Sheet

VaultYUSDT priced its shares by asking the strategy for its balance. According to the DeFiHackLabs reconstruction, the strategy computed that balance as its Convex position, BaseRewardPool.balanceOf(Strategy) multiplied by the Curve metapool's get_virtual_price(), plus its aUSDT and USDT.

The first mistake was trusting the Convex balance. Convex's BaseRewardPool has a stakeFor(address, amount) function that lets anyone stake LP tokens on behalf of any address, so the strategy's Convex balance could grow without the strategy ever depositing anything. The second was the price. get_virtual_price() reflects a Curve pool's internal accounting and doesn't track the market value of LP tokens when one asset in the pool has lost its peg. In the USDP/3CRV metapool, USDP had fallen to about $0.20 and the pool held 1,526,591 USDP against 3,263 3CRV, yet get_virtual_price() still reported about 1.0149.

Put together, anyone could push LP tokens into the strategy's books and have each one counted at roughly a dollar while it was worth far less. It's like a store that totals its inventory by counting whatever is on its shelves at the list price, when anyone can walk in and stock the shelves with knock-offs. A contract should only count as its own the assets it put somewhere itself, or it needs a way to tell earned balance from injected balance, and any price it uses for those assets has to hold up when the market doesn't.

Stocking the Strategy's Shelves

DeFiHackLabs lays out the sequence. After the Morpho flash loan, the attacker built up USDP/3CRV LP through two routes. The first ran USDT through Curve's 3pool, the LUSD metapool, a Yearn vault and a Balancer swap, capped by Balancer's 50% MAX_IN_RATIO at about 230K LP. The second bought depegged USDP directly and added it to the metapool, minting about 461K LP. The PoC notes that a Uniswap V4 unlock in the same transaction only served the USDP purchase.

The attacker then called stakeFor on the Convex BaseRewardPool, naming the Flamincome strategy as the beneficiary, and staked 691,647 LP. The strategy's reported value jumped, and so did VaultYUSDT's share price. A call to VaultYUSDT.withdrawAll() redeemed the attacker's shares at the inflated price, pulling real aUSDT and USDT out of the strategy. The flash loan was repaid in the same transaction.

Two Numbers for One Loss

Blockaid flagged the exploit and put the attacker's profit at about $345.9K, which matches the 345,902.67 USDT Etherscan shows reaching the sending wallet. The DeFiHackLabs PoC reproduces a net profit of 344,751 USDT and puts the strategy's gross loss at 597,352 USDT, which lines up with the roughly $595K DefiLlama lists. The strategy's 597,352 USDT is what the vault's depositors lost and the figure this post uses, while the roughly $346K is what the attacker kept after the costs of the trade.

Etherscan shows the full life of the wallet that sent the exploit transaction, 0x8338...6871, which made only six transactions. It received about 0.098 ETH from Tornado Cash's 0.1 ETH pool at 13:18:35 UTC, about half an hour before the attack. The exploit itself ran at 13:49:59 UTC as a contract deployment, so the whole drain executed inside the new contract's constructor. At 13:52:35 UTC the wallet swapped its USDT through the LI.FI aggregator and received about 144.06 ETH, and at 13:53:23 UTC it sent about 144.14 ETH on to 0x7B69...c306. Crypto Times reported the same Tornado Cash funding, the LI.FI interaction and a 144.15 ETH transfer, which matches that last outbound transfer.

How Olympix Catches a Balance Anyone Can Inflate

Olympix reads a vault the way an attacker does, as states, transitions and entry points, and takes in the context around it, including the external protocols a strategy plugs into. For VaultYUSDT, the state that matters is the strategy's reported balance, because every share price comes from it, and the engine maps every path that can move that number. A signal is a pattern that marks a path as dangerous, and Olympix's static analysis surfaces this one: an accounting function that reads an external balance a third party can increase without the strategy's involvement, then multiplies it by a price that isn't checked against market value.

The signal points at one function, but the damage only shows up when the vault, the strategy, Convex and Curve are taken together, and BugPoCer starts from that whole picture. Reading how VaultYUSDT turns the strategy's balance into a share price, it infers the rule the vault can't live without: the strategy's reported balance grows only when the strategy itself deploys capital or earns yield, so a redeemed share is never worth more than the real assets behind it. Counterexample-Guided Invariant Refutation then has it execute paths outward from that rule, including calls into the external protocols from addresses that aren't the strategy, and a stakeFor from an arbitrary address followed by a withdrawal breaks the rule. Olympix has flagged this class of balance-injection manipulation before in other codebases.

The output is a counterexample: a deposit at honest share price, a stakeFor that adds outside LP to the strategy's Convex position, a share price inflated by get_virtual_price() on a depegged pool, and a withdrawAll() that pays out real aUSDT, with the minimal conditions that trigger it and a generated Forge test that replays it. That's the September 16 drain, found in development instead of on mainnet.

Olympix runs automatically in development, at every merge and before release, so the check covers a strategy the day it's written and every time its integrations change, including integrations with protocols that didn't exist when the vault first shipped.

Count Only What You Put There

A vault's share price is only as trustworthy as the balance it's built on, and VaultYUSDT's balance could be raised by anyone with LP tokens to spare. Strategies that read balances from external protocols should track what they deposited themselves and price it at a value that survives a depeg. If your vaults or strategies read balances from protocols you don't control, book a technical walkthrough.

On-Chain References

Protocol: Flamincome (VaultYUSDT and strategy)

Chain: Ethereum

Date: September 16, 2026, 13:49:59 UTC (block 25,990,443)

Loss: 597,352 USDT lost by the strategy, about $597K (DeFiHackLabs); 345,902.67 USDT kept by the attacker after costs

Attacker: 0x8338...6871

VaultYUSDT (victim): 0x0461...Cc0F

Strategy proxy: 0xb8d6...68a5

Strategy implementation: 0xFf20...2AFB

Attack contract (created by the exploit tx): 0x1C7E...b486

Exploit tx: 0x5ff8...0d37

Funding tx (Tornado Cash): 0x2334...8d7b

USDT to ETH swap via LI.FI: 0x0906...5f84

144.14 ETH outbound transfer: 0x52de...4a95

Recipient of the 144.14 ETH: 0x7B69...c306

Sources

DeFiHackLabs PR #1266: Flamincome VaultYUSDT exploit PoC

SlowMist: Flamincome exploit alert

Crypto Times: Blockaid Flags FlamingoFinance Contract Exploit, $345.9K Stolen

Flamingo Finance: Flamincome, The Ultimate Yield Booster

More from Olympix:

No items found.

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