Ethereum
Accounting error

NovaBox's $107K Loss and How Olympix Would Have Prevented It

Loss
Loss
Exploit date
June 9, 2026

NovaBox went live on Ethereum on October 11, 2018, written in Solidity 0.4.25, and for close to eight years it did one job. Depositors put ETH and NOVA tokens into the contract, and it shared dividends among them in proportion to what each had contributed. At 18:48:59 UTC on June 9, 2026, a single transaction took the contract's ETH balance from about 65.11 ETH to 0.09 ETH, according to reporting by Bits.media, which put the number of affected depositors at more than 130.

On-chain, NovaBox paid out 65.02 ETH more than it took in during that transaction, worth about $106,556 at the time. The attacker's wallet kept 56.73 ETH of it, about $93,000, which is the figure most reports use. The rest, 8.08 ETH, went to the address that deployed NovaBox in 2018, through the contract's own payout logic.

How the Dividend Ledger Worked

NovaBox tracked dividends with a points system, a common pattern in contracts of that era. Each time ETH entered the dividend pot, a running total of dividend points went up. Each account had a checkpoint recording what that total was the last time the account was settled. An account's unpaid dividends were the gap between the running total and its checkpoint, multiplied by its contribution, so a depositor only ever earned the dividends that arrived after they did.

The contract kept separate pots for its 4% and 6% dividend streams, in both ETH and NOVA, and an internal function called updateAccount settled all of them at once. It paid out what an account was owed and then moved every checkpoint up to the current total. The math is cheap, since the contract never has to loop over every depositor when a dividend arrives, and that efficiency is why the pattern spread. That last step is what makes the whole scheme safe. A checkpoint that sits at zero tells the contract the account has been around since the very first dividend.

Two Assumptions That Didn't Hold

Defimon's analysis traces the flaw to addToList, the function that registers a new participant. It adds the account to the list and to the contract's totals, but it never sets that account's checkpoint for the 4% ETH stream. A newcomer therefore starts with a checkpoint of zero and, by the contract's own arithmetic, is owed a share of every 4% ETH dividend paid since 2018, scaled to whatever they deposited.

NovaBox's author had put a guard in front of ETH deposits. The fallback function reads the caller's code size with extcodesize and requires it to be zero, with a comment in the verified source saying it shouldn't allow contracts to deposit ether. The idea was to keep deposits to ordinary wallets. A contract that's still being deployed has no code yet, though, so extcodesize returns zero for it, and the June 9 transaction was itself a contract deployment. The ETH that reached NovaBox came from a contract created inside that deployment, which passed the check as if it were a wallet.

Together, the two gaps meant a fresh contract could join with a large deposit, be credited with a historical dividend share it never earned, and settle in the same transaction. Defimon reports that the deposit was funded with a 427.5 WETH flash loan from Aave and that the dividend payout came to 145.82 ETH. Because dividends were calculated against the new, large contribution, the payout was far bigger than anything the account could legitimately have earned.

Following the 65 ETH

The transaction trace shows the money moving in a tight loop. NovaBox received 427.5 ETH from the newly created contract and sent back 338.62 ETH of principal plus the 145.82 ETH dividend. It also paid 3.80 ETH and 4.28 ETH to its deployer's address. The flash loan was repaid with 427.71 WETH, and the remaining 56.73 ETH went to the attacker's wallet.

The dividend was paid from the ETH that NovaBox held for its existing depositors, which is why the contract's balance fell to almost nothing. Security firm F12 described the incident as a flaw in the reward mechanism's logic. In code terms, that logic is a single missing checkpoint assignment, sitting in the contract's verified source, plus a deposit guard that couldn't tell a contract under construction from a wallet.

As of November 6, 2026, no statement from the NovaBox team about the incident had turned up in public sources.

Why a 2018 Contract Still Paid Out in 2026

Points-based dividend contracts carry a quiet obligation. Every path that creates or enlarges a position has to settle the account and move its checkpoints first, and every checkpoint has to be set before the account starts earning. NovaBox settled accounts in many places, including deposits and withdrawals, and missed one write in the path that adds a new participant. That single omission sat dormant until someone with enough capital decided to enter fresh.

The extcodesize check deserves its own lesson. Checking code size has never been a reliable way to tell wallets from contracts, because of exactly this construction-time window. Any contract that relies on it for safety should be treated as reachable by contracts too.

How Olympix Would Have Exposed the Zero Checkpoint

Olympix reads a contract as an attacker would, as states, transitions and entry points, and then infers the invariants those pieces are meant to protect. In NovaBox, the states that matter are each account's contribution and its dividend checkpoints, and the invariant follows directly from how the ledger is built: an account can never be owed dividends that were distributed before it joined.

BugPoCer would have run Counterexample-Guided Invariant Refutation from the contract outward, mapping every path that registers a participant or changes a contribution and searching for one where the amount owed exceeds what arrived after the account's entry. The path through addToList breaks that rule on the first try, because the account enters with a checkpoint of zero while the running total is already high. The search would also have treated the extcodesize guard as one more condition to satisfy, and found that a contract in its constructor passes it.

The output would have been a counterexample with the minimal conditions, a pool with past dividends and a new participant entering through the unsettled path, along with a generated Forge test that replays it. That test would have been the June 9 drain, reproduced in development before the contract was ever deployed.

The Takeaway for Reward Contracts

A dividend ledger is only as sound as the moment an account enters it. Initialize every checkpoint when an account is created, settle before any contribution changes, and don't lean on code-size checks for safety. To see how Olympix tests the accounting invariants in your own contracts and returns a runnable counterexample for each one that breaks, book a technical walkthrough.

On-Chain References

Exploit tx (June 9, 2026, 18:48:59 UTC, block 25281768): 0x0cfa...8844

Attacker EOA: 0x3690...C294

Attack contract (created by the exploit tx): 0xB50b...0858

NovaBox contract: 0xbc41...46b0

NOVA token: 0x72fb...ec9f

NovaBox deployer: 0x01e8...237a

NovaBox deployment tx (October 11, 2018): 0x53b9...da02

See what Olympix finds on your own code

Send us a repo that's already been audited, and we'll run Olympix at the same commit and show you what comes back.