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

BiFi Lending's $165K Loss and How Olympix Would Have Prevented It

Date: October 17, 2026

Chain: Ethereum

Loss: 165,575 USDT drained, about $165K, of which 159,103.65 USDC was later returned

Class: stale interest accounting multiplied by a utilization rate a flash loan can move

BiFi Lending's USDT market on Ethereum had gone about 264,000 blocks without anyone touching it, roughly 36 days of silence. At 05:42:59 UTC on October 17, 2026, an address deployed a contract built to drain it. Twelve seconds later, in the next block, a different contract run by the MEV operator c0ffeebabe.eth ran the same attack before the deployer's contract was ever called, borrowed 40.5 million USDT in a flash loan, and pulled 165,575 USDT out of the market in a single transaction.

None of it came from breaking an access check or stealing collateral, and most of it came back the next day. BiFi works out deposit interest by multiplying the number of blocks since the market's last action by the market's current interest rate, and after a 36-day gap that block count was enormous, while the rate it was multiplied by came from a utilization figure the attacker could push up inside the same transaction.

How BiFi Counts Interest

BiFi is a lending protocol where users deposit assets and borrow against them. Its public repository describes a dedicated Market Handler contract for each asset, coordinated by a Market Manager. Instead of updating every user's balance every block, each handler keeps a running exchange rate, called the global EXR, that grows as interest accrues. A user's balance catches up by comparing the global EXR with the rate recorded at their own last action.

The global EXR doesn't update on its own. It moves when someone uses the market. In the repository's TokenHandler, the first action in a new block runs _checkFirstAction(), which measures how many blocks have passed since the last update, stores that gap as inactiveActionDelta, and snapshots the current rate as actionEXR. Every action in that block then recalculates the global EXR from the same two stored values. The interest model's formula is rate times delta plus one, multiplied by actionEXR, and the rate comes from the market's current deposit and borrow totals, its utilization.

A 36-Day Gap Meets a Live Rate

Normally the delta is a few blocks and the rate barely changes within a block, so the product stays small and accurate. In a market nobody has used for 36 days, the delta is about 264,000 blocks. The rate the formula multiplies it by is whatever utilization the market shows at that moment, so the gap gets priced at the current rate as though that rate had held for all 36 days, during which the market saw no activity at all.

Per Defimon's alert, once the first action stored the 36-day delta and froze actionEXR, every later action in the same block recomputed the global EXR from that gap times the current utilization. An attacker who could raise utilization inside that block could make the market believe it had earned 36 days of interest at a rate it never actually paid.

The teaching moment is that a time gap and a rate have to describe the same period. Multiplying a long historical interval by a value read right now is only correct if that value can't change during the transaction doing the multiplying. It's like billing a parked car for a month at whatever the meter says during the five minutes the driver spends moving it.

One Flash Loan, Thirty-Six Days of Interest

The address 0x7c78...c4C6 deployed its exploit contract in block 26210255. That contract was never called. In block 26210256, c0ffeebabe.eth sent a transaction through its own bot contract that, in Defimon's words, front-ran the deployer by replaying the attack. The explorer shows the bot taking a flash loan, capital borrowed and repaid within one transaction, of 40.5 million USDT from Morpho and depositing it into BiFi's USDT handler in five growing tranches, the largest about 30.86 million USDT.

According to Defimon and SigIntZero's trace, the bot then borrowed about 30 million USDT back out of the same market to push utilization up and ran a loop of repays and withdrawals that cashed out the inflated deposit interest. It ran the cycle twice. SigIntZero puts the handler's net outflow at 165,575.15 USDT, which the bot swapped for 68.06 WETH before repaying Morpho, with about 0.99 ETH of that going to the block builder that placed the transaction first in the block.

The Money Comes Back

At 17:21:59 UTC on October 18, c0ffeebabe.eth sent 159,103.654838 USDC to BiFi's USDT handler. SigIntZero reports that this was the proceeds of selling the 67.07 ETH the operator kept, and attributes the roughly $6,500 gap to the builder payment and ETH's price move between the drain and the refund. SigIntZero notes that the same operator returned about $5.4 million to the Curve deployer after front-running an attack on Curve pools in July 2023, and that address poisoners began spraying lookalikes of BiFi's handler address into c0ffeebabe's history within 12 minutes of the refund. As of October 19, 2026, BiFi hadn't posted about the incident on its X account.

How Olympix Tests Interest Math Against the Clock

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and takes in its surrounding context, including how the protocol is meant to accrue interest, to infer invariants the system depends on but never writes down. For BiFi's handler, the invariant in one sentence is that the interest credited for any stretch of blocks must reflect the utilization that actually prevailed during those blocks, so no action inside a single transaction can raise what depositors earned in the past.

The engine maps every path through the handler's actions and uses signals to choose which ones to attack. The signal here is an accrual formula that multiplies a stored, possibly very large block delta by a rate derived from live deposit and borrow totals, which any caller can move in the same block. Olympix's static analysis surfaces that pattern, and Olympix has flagged a close cousin of this class before in other codebases, where issuance claims are priced off a spot multiplier an attacker can manipulate.

BugPoCer turns that signal into a test of the accrual rule. Counterexample-Guided Invariant Refutation starts from what the market as a whole owes its depositors and works outward to the transactions that could overpay them, and for a handler like this one the interesting variable is time. It lets the market sit idle for a long stretch of blocks, then runs a first action followed by a utilization change in the same block, and compares the interest the global EXR now credits with what the pool actually earned while it sat untouched. Once the idle gap is long enough, the credited interest outruns the real earnings, and that's the break. The counterexample is the concrete sequence, the minimal conditions that trigger it (a long idle period and a utilization swing within one block) and a generated Forge test that replays it, which is the October 17 drain produced in development instead of on mainnet.

Because the engine runs during development, at every merge and before release, it tests the states a live market drifts into, like a market that goes quiet for a month, alongside the states a test suite usually starts from.

When the Quiet Market Is the Risky One

BiFi's interest model behaved sensibly for an active market, where the gap between actions is short and the rate barely moves. It broke in the one state a typical test suite rarely reaches, a market left idle long enough for the delta to dominate. Lending teams can bound the delta, snapshot the rate at the start of the gap, or time-weight it, and the useful check is to run every accrual path against a long-idle market before release. To see Olympix run that check on your own lending code, book a technical walkthrough.

On-Chain References

Protocol: BiFi Lending (USDT market, TokenHandler)

Chain: Ethereum

Date: October 17, 2026, 05:43:11 UTC

Loss: 165,575.15 USDT net outflow (SigIntZero); 159,103.654838 USDC returned on October 18

Market inactivity before the attack: about 264,000 blocks (about 36 days)

Victim (BiFi UsdtHandlerProxy): 0x808C...A9E3

Original attacker EOA: 0x7c78...c4C6

Original exploit contract (never called): 0x8C0D...7B92

Exploit contract deployment tx (block 26210255): 0x15b4...a034

Drain tx by c0ffeebabe.eth (block 26210256): 0x756c...ad14

c0ffeebabe.eth: 0xC0ff...9671

c0ffeebabe bot contract: 0xE08D...D015

Flash loan source (Morpho): 0xBBBB...FFCb

Refund tx (159,103.65 USDC, October 18, 17:21:59 UTC): 0x9702...eaeb

Sources

Defimon: BiFi Lending exploit alert

SigIntZero: BiFi $165K, a 36-Day Idle Market Let One Caller Inflate the Rate on a Month of Interest

bifrost-platform/BIFI: BiFi smart contracts on GitHub

More from Olympix:

No items found.

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