
Date: September 17, 2026
Chain: Starknet
Loss: about $3.5M in borrowed assets
Class: collateral priced from a thin, manipulable source with no deviation or liquidity guard
At 05:37:10 UTC on September 17, 2026, the Pragma oracle feeding Nostra Finance's money market recorded a price for NSTR, Nostra's governance token, of $0.00596118, which was roughly what NSTR traded for. Ten minutes later, at 05:47:54, another entry for the same token came in at $99.02, and Nostra's money market blended the two into a collateral price of about $49.52.
At that price, about 70,686 NSTR with a real market value of roughly $421, according to one independent reconstruction, was enough to borrow about $3.5 million in ETH, STRK, USDC.e, USDT, WBTC and DAI in under three minutes. To get there, the attacker created a tiny NSTR/SolvBTC pool, got one of Nostra's two price sources to read from it, and let Nostra average a real price with a fabricated one.
Nostra is a lending and borrowing protocol on Starknet, and NSTR is its governance token. Its money market works with tokenized positions: when an account borrows, the market mints it a debt token for that asset, such as dETH for ETH, and the account's deposits back that debt as collateral. The Voyager explorer labels the ETH debt contract "Nostra: ETH Debt," and the interface published for its class lists links to a cdp_manager, the component that tracks each collateralized debt position, to an interest rate model and to the underlying asset. The class itself is marked unverified, and we couldn't find published source for the code that combines oracle prices and sets borrow limits, so this post describes that logic from the sources and quotes no code.
NSTR was accepted as collateral, with its price delivered through Pragma, a Starknet oracle network. NSTR was a small market, with an estimated circulating market cap of about $550,000 that morning according to BeInCrypto, and Nostra's TVL stood at about $4.15 million the day before, according to DefiLlama figures cited by Rekt.
Pragma's design has two layers. Publishers submit prices for each source, and Pragma takes the median of their values per source, and according to Rekt, the consuming protocol then decides how to combine the source-level prices into one. For NSTR only two sources contributed, an AVNU-derived price and a GeckoTerminal-derived price. Pragma says it had already classified NSTR as a high-risk feed because of thin liquidity and few sources, that it had raised those risks with Nostra, and that Gate.io had earlier been removed as an NSTR source at Nostra's request over illiquidity concerns. Pragma also says it recommends at least three sources, that an enforced three-source minimum would have rejected the manipulated response, and that it found no decimal or median-calculation error.
GeckoTerminal picks a reference pool to quote each token's price, and an attacker who controls the pool it picks controls the quote. According to GoPlus Security's reconstruction as reported by Rekt, the attacker had accumulated NSTR in March and August, months ahead of the attack. At 05:23:29 UTC on September 17, in Starknet block 14998567, a new NSTR/SolvBTC pool was created and seeded with about 1.5 SolvBTC of one-sided liquidity, and Halborn describes GeckoTerminal selecting that pool as NSTR's reference.
With almost no depth behind it, a small trade could move the pool's quoted price a long way. At 05:47:19 UTC, in block 14999408, the attacker's trading account at 0x2d9f...da23 made the buy that pushed the quote from a fraction of a cent to just over $99. Thirty-five seconds later, at 05:47:54 UTC in block 14999429, that quote entered Pragma as the GeckoTerminal-derived entry. The AVNU-derived entry from 05:37:10 still said $0.006, and the midpoint of the two, about $49.52, became the value Nostra used for NSTR collateral. One independent reconstruction puts the borrow-time NSTR/ETH rate at 0.02032399 against a real rate of about 0.00000244689, roughly 8,306 times too high.
An average only protects you when most of what goes into it is honest, and with two inputs a single bad one moves the result halfway to wherever the attacker wants, the way a two-person jury where one juror has been bribed can still deliver whatever verdict the briber needs once the votes are split down the middle. Pragma's per-source median did its job inside each source, and according to Rekt, Nostra's combination step produced exactly the output its configuration allowed.
A lending protocol that accepts a thin token as collateral needs to refuse prices that disagree wildly with each other, or that can't be backed by real liquidity, before it lets anyone borrow against them. As Pragma put it afterward, a price recorded in a thin market doesn't establish that meaningful amounts of collateral can be liquidated at that price. Pragma's later assessment measured exactly that, the price a liquidator would actually get selling $10,000 of each asset, and found NSTR's effective price on a $10,000 sale about 15% worse than on a $10 sale, enough to rate the feed critical risk.
The attacker's Starknet account at 0x06d4...4bc3, a Braavos smart wallet, posted its NSTR and borrowed against it in seven transactions that Voyager timestamps between 05:48:53 and 05:51:35 UTC. BlockSec's Phalcon itemized them at September 17 prices.
The first, at 05:48:53 in block 14999465, borrowed 939.30 ETH, about $2.30 million, by minting 913.74 dETH to the attacker's account on the Nostra: ETH Debt contract. STRK followed at 05:49:19, 28,272,985.90 STRK worth about $819,000, then 113,661 USDC.e at 05:49:32 and 84,377 USDT at 05:49:44. The first WBTC borrow, 2 WBTC, landed at 05:50:28, then 29,078 DAI at 05:50:49, and a second WBTC borrow of 0.88 at 05:51:35, bringing WBTC to 2.88, about $219,900. Phalcon's total is about $3.56 million, more than six times NSTR's entire market cap, all from a single account holding collateral worth a few hundred dollars at real prices.
The proceeds were sold in about 80 swaps across AVNU, Ekubo and JediSwap and moved through transit accounts to Ethereum using NEAR Intents, according to GoPlus, with AMLBot also naming CCTP and LayerZero OFT as routes. Two transit accounts received 1.2 million and 1.0 million STRK. PeckShield reported that about $1.92 million had reached Ethereum as 234.57 ETH and 1.3 million DAI. CertiK placed about $1.55 million still on Starknet and about $1.93 million at an Ethereum address, and AMLBot put about $1.6 million still at the Starknet address the next morning. Halborn reports Nostra's TVL fell from about $4 million to roughly $710,000.
On October 4, between 21:59 and 22:03 UTC, the Ethereum wallet that Rekt's reconstruction ties to the consolidated proceeds sent 10 ETH and then 243.47 ETH to a fresh address. On October 20, 2026, the explorer shows that address holding about 253.47 ETH and 1.35 million DAI, roughly $1.95 million, with no outgoing transactions since. Voyager now shows a note from the Starknet Security Council on the attacker's borrowing account, asking whoever owns it to get in touch about the Nostra incident.
Nostra confirmed the unauthorized borrowing of about $3.5 million in a post on X on September 17 and paused its money market, which stopped lending, borrowing, withdrawals and liquidations. It said the final loss and any recoveries weren't yet known and promised a detailed post-mortem, and Rekt's September 23 write-up reported the market still paused with no post-mortem published. As of October 20, 2026, that September 17 post was still the latest on Nostra's X account, with no post-mortem, recovery or compensation announcement after it. On September 18, Pragma published an assessment of its own feeds that rated NSTR among six critical-risk feeds out of 22 on mainnet, alongside BROTHER, DAI, DOG, EKUBO and LORDS, and named its own feeds as part of the failure chain.
Rekt also lists earlier price-feed trouble at Nostra. In March 2025, feed errors overstated xSTRK and sSTRK about threefold with no secondary oracle available, and in August 2025 a non-functional Pragma-supplied xSTRK feed left four accounts undercollateralized with about $14,212 in bad debt that Nostra Labs covered.
Nostra says its contracts were audited by Trail of Bits, Cairo Security Clan and Salus, and Rekt notes that neither its FAQ nor its terms page links the reports, dates or scope. The loss came from the meeting point of three separately built pieces, an aggregator's pool selection, an oracle's per-source pricing and the money market's way of combining sources, which is exactly the kind of interaction an audit scoped to one codebase in a fixed window can't fully see, and Rekt found no evidence that GeckoTerminal's pool-selection safeguards had been audited or disclosed at all.
Nostra's money market is written in Cairo for Starknet, so this section describes how the engine treats the on-chain pricing logic itself, the code that combines source prices and feeds the borrow limit. Olympix reads a protocol the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, including where its prices come from and how deep those markets are, to infer the invariants the system depends on. In Nostra's money market, the state that matters is the collateral value assigned to each account, and the entry points that matter are every borrow, every debt-token mint and every withdrawal that trusts it.
Olympix's static analysis surfaces the signal in the collateral pricing path: a price for a collateral asset combined from as few as two sources, with no check on how far those sources disagree, no time-weighted fallback and no cap tied to the asset's real liquidity, passed straight into the borrow limit. Olympix has flagged this class before in other codebases. From that signal, the engine narrows from every path, to the feasible ones that end in a borrow, to the paths whose borrow limit depends on that combined price, which is where the invariant lives: no account should be able to borrow more than its collateral could actually be sold for.
BugPoCer goes after that rule directly. Running Counterexample-Guided Invariant Refutation over the money market and the price feed it consumes, it treats each oracle source as a value an outsider might influence and executes borrow paths until one lets an account take out more than its collateral could be sold for. Symbolic execution supports that search by solving for the source values that push a borrow over the line, and the same engine component also serves BugScout, which approaches pricing paths from the signal end with known oracle-manipulation strategies.
For this exploit, the counterexample would contain a collateral asset with two price sources, one held at its market price and one set thousands of times higher, the combined midpoint passing into the borrow limit unchecked, a deposit of a small amount of that collateral, and a sequence of borrows across the market's assets whose total exceeds what the collateral could be sold for. It would state the minimal conditions, two sources and no deviation or liquidity bound, and it would come with a generated replay test that sets the two source prices, posts the collateral, runs the borrows and asserts that the account's debt exceeds the collateral's real value. That's the September 17 borrow produced in development instead of on Starknet.
Because this runs automatically in development, at every merge and before release, the change that would have surfaced it is the one that made a two-source feed eligible to back borrowing, whether that's listing NSTR as collateral or accepting the feed configuration after Gate.io was removed, and the check would repeat at every later release while the configuration stood.
Nostra's loss came from a token that was real, a pool that was real and a price that was technically recorded, all combined into a number nobody could have sold NSTR for. For builders listing smaller tokens as collateral, the safe default is to treat source disagreement and shallow liquidity as reasons to refuse a borrow, and to test that refusal under an attacker's inputs. To see how Olympix maps every price your contracts lend against and returns a runnable counterexample where one can be pushed past what the collateral is really worth, book a technical walkthrough.
Protocol: Nostra Finance money market
Chain: Starknet
Date: September 17, 2026, oracle entries at 05:37:10 and 05:47:54 UTC, borrows from 05:48:53 to 05:51:35 UTC
Loss: about $3.5M (Nostra); about $3.56M itemized by BlockSec/Phalcon
Attacker account (borrows): 0x06d4...4bc3
Attacker account (thin-pool trading): 0x2d9f...da23
Nostra: ETH Debt contract: 0x00ba...2e74
NSTR/SolvBTC pool creation tx (05:23:29 UTC, block 14998567): 0x741a...e69d
Price-moving trade tx (05:47:19 UTC, block 14999408): 0x772e...7ac1
AVNU-derived oracle entry tx (05:37:10 UTC, block 14999048): 0x1d33...8b7f
GeckoTerminal-derived oracle entry tx (05:47:54 UTC, block 14999429): 0x6bc9...1cf1
Exploit tx, ETH borrow (939.30 ETH, 05:48:53 UTC, block 14999465): 0x2460...f00e
Exploit tx, STRK borrow (05:49:19 UTC): 0x7900...b820
Exploit tx, USDC.e borrow (05:49:32 UTC): 0x34bb...200a
Exploit tx, USDT borrow (05:49:44 UTC): 0x61ea...0647
Exploit tx, WBTC borrow (first, 05:50:28 UTC): 0x373b...8fb4
Exploit tx, DAI borrow (05:50:49 UTC): 0x5a8a...c54d
Exploit tx, WBTC borrow (second, 05:51:35 UTC): 0x439a...ce95
Transit account 1 (1.2M STRK): 0x0285...321d
Transit account 2 (1.0M STRK): 0x074f...b57e
Ethereum consolidation wallet (per Rekt's reconstruction): 0xa059...3c37
Transfer to new wallet, 10 ETH (October 4, 21:59:47 UTC): 0xadb5...0a0e
Transfer to new wallet, 243.47 ETH (October 4, 22:02:47 UTC): 0x929a...d3e7
New holding wallet (about 253.47 ETH and 1.35M DAI): 0x9166...00B0
Halborn: Explained, The Nostra Finance Hack (September 2026)
Nostra: Incident statement on X
SpendNode: Pragma Flags 6 Price Feeds as Critical Risk After $3.5M Starknet Exploit