Makina Finance DUSD/USDC Curve MachineShareOracle Permissionless updateTotalAum() Spot-Price Manipulation Drain (2026-01-20)

  • Name: Makina Finance DUSD/USDC Curve MachineShareOracle permissionless updateTotalAum() spot-price manipulation drain
  • Date: 2026-01-20
  • Protocol: Makina Finance
  • Chain: Ethereum
  • Category: oracle manipulation / vault strategy-path valuation manipulation / permissionless accounting publication / Curve pool drain
  • Loss: about 1,299.17 ETH initially extracted, roughly $4.13M at the time; Makina later recovered the majority through whitehat / MEV negotiations and LP restitution
  • Summary: On 2026-01-20, an attacker prepared a flash-loan oracle manipulation against Makina’s DUSD Machine, but an MEV searcher front-ran the original exploit and captured the profit first. The exploit path used about 280M USDC of flash liquidity to distort Curve state relevant to a DUSD Machine accounting instruction for a MIM/3CRV position. That instruction valued the position through calc_withdraw_one_coin(), so the manipulated pool returned an inflated one-sided withdrawal quote. Makina then let that quote flow permissionlessly and atomically through Caliber AUM, Machine AUM, and the Machine exchange rate, while the external DUSD/USDC Curve pool oracle relayed the inflated exchange rate straight into pool pricing. The attacker bought DUSD at the fair pool price, inflated the Machine AUM mid-transaction, sold DUSD back to the pool at the manipulated oracle price, repeated the loop twice, and drained the pool’s USDC while the underlying Machine assets themselves remained intact.
  • Trigger / entry point:
    • Makina’s DUSD Machine used approved Weiroll-based accounting instructions to value strategy positions and aggregate them into Caliber AUM and then Machine AUM.
    • One DUSD accounting instruction for a Curve MIM/3CRV position priced the position through calc_withdraw_one_coin(), i.e. a hypothetical one-sided unwind quote derived from live Curve pool state.
    • Position value updates were permissionlessly triggerable, and the Hub Caliber AUM could be updated in the same block as Machine AUM.
    • The external DUSD/USDC Curve pool oracle synchronously consumed the current Machine exchange rate, so a manipulated same-block AUM update immediately became secondary-market pricing truth.
  • Root cause:
    • Makina treated a manipulable strategy-unwind quote as if it were durable AUM truth for the DUSD Machine.
    • The dangerous part was not just the Curve read itself; it was the full publication pipeline: permissionless accounting updates, same-block propagation from Caliber to Machine AUM, and a synchronous external pool oracle that relayed the inflated exchange rate without delay or deviation guard.
    • In practice, Makina combined three assumptions that failed together: that calc_withdraw_one_coin() was a safe valuation surface, that anyone could publish that valuation immediately, and that the downstream Curve pool could safely consume the new Machine exchange rate inside the same transaction.
  • Exploit path:
    1. The original attacker deployed an attack contract at 0x2c19b916b29e5170f75628d690623dedcafeca4c in block 24273361 via tx 0xad945d38ec5dc00f0310b6f22d19da3b8b5063b9f3e7efb38ca6a5cbc6385a39.
    2. One block later, MEV searcher 0x935bfb495E33f74d2E9735DF1DA66acE442ede48 front-ran the planned exploit in tx 0x569733b8016ef9418f0b6bde8c14224d9e759e79301499908ecbcd956a0651f5.
    3. The exploit borrowed about 280M USDC through flash loans, commonly broken out as roughly 160.59M USDC from Morpho and 119.41M USDC from Aave V2.
    4. The attacker used roughly 170M USDC to skew the relevant Curve paths so the MIM/3CRV accounting instruction’s calc_withdraw_one_coin() call returned an inflated 3CRV value for the DUSD Machine’s held position.
    5. While that manipulated state was live, the attacker triggered Makina’s accounting publication path through the Caliber contract, causing the inflated position value to update Caliber AUM and then Machine AUM in the same transaction.
    6. Because the DUSD/USDC Curve pool oracle read the Machine exchange rate synchronously, the manipulated AUM immediately repriced DUSD inside the external Curve pool.
    7. The attacker first bought DUSD from the pool at the fair rate, then sold it back into the now-mispriced pool at the inflated oracle price, and repeated this cycle twice until the pool’s USDC was exhausted.
    8. The profits were converted into about 1,299.17 ETH; the MEV searcher kept 0.13 ETH, sent about 1,299.04 ETH to builder 0xa6c248384c5ddd934b83d0926d2e2a1ddf008387, and the builder later split 1,023 ETH to 0xbed26250Db2097318386F540fD546acEDf7bdE25 plus 276.32 ETH to a Rocket Pool node operator path.
  • What the attacker needed to be true:
    • The DUSD Machine had to value the MIM/3CRV position from a live Curve unwind quote rather than from a delayed or manipulation-resistant valuation surface.
    • Accounting publication had to remain permissionless so the attacker could choose the exact block and exact manipulated market state that got written into Caliber AUM.
    • Hub Caliber AUM and Machine AUM had to be updatable in the same block, so flash-loan capital could carry the entire exploit without multi-block inventory risk.
    • The external DUSD/USDC Curve pool oracle had to relay the Machine exchange rate immediately, with no deviation guard or settlement delay.
    • The DUSD/USDC pool needed enough USDC liquidity for the attacker to monetize the dislocation before recovery mode was triggered.
  • Technical anatomy worth remembering:
    • This was not a case where the Machine treasury itself was directly drained. Makina’s own postmortem stresses that the losses were isolated to LPs in the DUSD/USDC Curve pool; the underlying assets held inside the Machines were not stolen.
    • The critical valuation surface was a hypothetical one-sided unwind helper, calc_withdraw_one_coin(). Makina converted that execution-path quote into accounting truth, then downstream infrastructure treated that accounting truth as money-good price information.
    • The exploit path crossed three modules that should be analyzed as one security boundary: the accounting instruction, AUM publication pipeline, and external Curve pool oracle.
    • Same-block propagation mattered. If the manipulated Caliber valuation had not been able to reach Machine AUM and then the Curve oracle inside one flash-loan transaction, the exploit would have required much more capital and much more inventory risk.
    • The exploit is a clean reminder that permissionless bookkeeping is not operationally harmless when the bookkeeping verb itself publishes reserve-spending or pool-pricing truth.
  • Representative transactions and addresses:
    • Attack-contract deployment tx: 0xad945d38ec5dc00f0310b6f22d19da3b8b5063b9f3e7efb38ca6a5cbc6385a39
    • Main exploit tx: 0x569733b8016ef9418f0b6bde8c14224d9e759e79301499908ecbcd956a0651f5
    • DUSD Recovery Mode tx: 0x69c504ce32a1df9d6302c1bbb937026eecb4488cef87420ce2a738b71966df45
    • DETH / DBIT Recovery Mode tx: 0x1d46ca565f38d39b58044200882c5efe6732fa7b8c1de1aa7b00586e5cdb34d4
    • Majority-funds return tx from 0xbed...: 0x0d23fea549bf8330cf47fabec75ad12b75cf0ade45cce68785067f2bda326a44
    • Permissioned-accounting enable tx: 0x2de76287a12a0c9fa60282a683b2a4e221ddc4526bd33ee16562886f4bbf718b
    • Curve DUSD/USDC pool: 0x32E616F4f17d43f9A5cd9Be0e294727187064cb3
    • Caliber contract highlighted in public technical writeups: 0x06147e073B854521c7B778280E7d7dBAfB2D4898
    • Original attacker deployer EOA: 0x2F934B0Fd5c4f99BAb37d47604a3a1AEADEF1CCc
    • MEV searcher: 0x935bfb495E33f74d2E9735DF1DA66acE442ede48
    • Builder / relay recipient: 0xa6c248384c5ddd934b83d0926d2e2a1ddf008387
    • Main returned-funds address: 0xbed26250Db2097318386F540fD546acEDf7bdE25
  • Response / mitigation:
    • Makina’s Security Council quickly placed DUSD, then DETH and DBIT, into Recovery Mode, pausing exchange-rate updates, deposits, and redemptions while the incident was contained.
    • The team coordinated recovery with SEAL911, builders, and the Rocket Pool validator path, ultimately recovering the majority of the extracted ETH and distributing refunds to affected LPs.
    • On the code side, Makina’s postmortem says the protocol hardened the architecture by making accounting optionally permissioned and by adding Machine exchange-rate deviation guards before restoring normal operation.
    • Makina upgraded to v1.1, enabled permissioned accounting for deployed Machines on 2026-01-26, and then turned Recovery Mode off once the new controls and refund process were in place.

Pattern tags

  • Hypothetical strategy-unwind quote promoted into solvency truth: Makina treated calc_withdraw_one_coin() on a live Curve MIM/3CRV path as if it were durable treasury value rather than an attacker-shapeable one-sided exit quote.
  • Permissionless accounting publication: the exploit needed more than a bad read; it needed a public path that let the attacker choose the exact manipulated block state that became canonical Caliber AUM and then Machine AUM.
  • Same-block internal-to-external oracle propagation: the dangerous publication chain was strategy quote -> Caliber AUM -> Machine AUM -> Machine exchange rate -> DUSD/USDC Curve pool pricing with no meaningful settlement delay or deviation quarantine.
  • Split balance-sheet monetization rail: Makina’s Machines stayed backed while external DUSD/USDC LPs absorbed the loss, so the protocol’s internal treasury truth and the downstream reserve-spending venue were not the same balance sheet.

Why the exploit worked

  • The attacker did not need to falsify Makina’s whole treasury. They only needed to distort one execution-path valuation surface long enough for Makina to publish it as canonical AUM. Once the MIM/3CRV instruction’s calc_withdraw_one_coin() output was inflated, the protocol itself carried that manipulated quote across the rest of the accounting stack.
  • Makina collapsed three separate questions into one same-transaction authority step: this one-sided Curve unwind quote exists, this quote now counts as canonical Machine AUM truth, and this newly published Machine exchange rate deserves immediate external pool-pricing authority. The exploit worked because the system treated all three as the same claim.
  • Permissionless publication was the key amplifier. If the strategy quote had been hard to publish, delayed, or bounded, the manipulated read would have remained a bad observation. Instead, the attacker could pick the exact flash-loan-distorted block state that Caliber and then the Machine would canonize.
  • The monetization venue sat downstream. Makina’s own postmortem is clear that Machine-held assets were not directly stolen; the loss crystallized because the external DUSD/USDC Curve pool honored the freshly inflated Machine exchange rate against real USDC liquidity before any independent check, cooldown, or deviation guard intervened.
  • Same-block composability removed most inventory risk. The exploit only became practical at this size because position read -> AUM update -> exchange-rate update -> external pool repricing could complete inside one transaction, letting the attacker buy DUSD fairly, publish the inflated mark, and sell back into a mispriced pool before normalization.

Detection and audit pivots

  • Inventory every strategy valuation helper that uses hypothetical unwind paths such as calc_withdraw_one_coin(), get_dy(), spot redemption previews, or one-sided exit math. Treat those helpers as execution-path quotes first, and only later ask what extra controls would be needed before they become treasury or exchange-rate truth.
  • Draw the full publication graph, not only the first bad read. Makina’s exploitable object was the chain instruction output -> Caliber AUM -> Machine AUM -> Machine exchange rate -> external pool oracle. If one public call can push value through that whole graph in one transaction, the protocol has already built a flash-loan-sized publication rail.
  • Ask whether internal AUM publication and downstream reserve spending sit on different balance sheets. If an internal accounting update can stay locally solvent while an external AMM, pool, or wrapper user base absorbs the loss, reviewers should model the downstream venue as the true payout surface.
  • Monitor for sudden AUM or exchange-rate jumps followed immediately by external-pool imbalance, heavy one-sided trading, or same-block update then dump behavior. The dangerous signal is not only AUM changed; it is AUM changed and a deeper liquidity venue spent against it before time passed.
  • Treat public accounting verbs as oracle operators. updateTotalAum() and related publication helpers deserve the same review as explicit price updaters because the caller is choosing when attacker-shaped state becomes canonical machine truth.
  • Model mempool races explicitly. Makina’s original exploiter was front-run one block later by an MEV searcher, which is the reminder that once a one-transaction publication exploit exists, the relevant adversary is every searcher who can see and replay the path.

Why this incident matters

  • Makina is a sharp modern example of an execution-path valuation bug escaping the vault boundary and poisoning external pool pricing. The exploitable object was not merely a thin AMM price; it was a hypothetical strategy unwind quote that Makina itself elevated into canonical AUM.
  • It also preserves the publication-authority lesson. A bad read is one problem; a permissionless same-block path that can publish that bad read into every downstream consumer is the real multiplier.
  • The incident is also worth preserving because the original exploiter did not even capture most of the payout. An MEV searcher copied the attack one block later, showing how quickly any publicly visible one-transaction exploit path becomes a race among adversaries once the architecture allows it.

Failure-prevention checklist

  • Do not let hypothetical execution quotes such as calc_withdraw_one_coin() become canonical treasury or exchange-rate truth without an explicit manipulation model. If the quote represents what a one-sided unwind might return right now, it is routing information first and solvency information only after hard additional controls.
  • Separate valuation publication from immediate downstream consumption. A strategy-position re-mark, Caliber AUM update, Machine AUM update, and external pool oracle refresh should not all be composable inside one flash-loan-sized transaction.
  • Treat accounting-update authority as oracle authority. If updateTotalAum() or an equivalent verb can reprice user-redemption value or external pool curves, gate it with role controls, keeper allowlists, delayed settlement, rate limits, or circuit breakers.
  • Add deviation guards and velocity caps to Machine exchange-rate updates, especially when the new mark depends on one-sided exit math from imbalance-sensitive pools.
  • Require strategy valuation to survive realistic unwind size. If a position can only realize the quoted value under a heavily one-sided exit assumption, do not let that quote define share value or secondary-market oracle truth at full size.
  • Break same-block publication chains. A manipulated strategy read should not be able to propagate from internal accounting to an external trading venue before arbitrage, governance, or operators have any chance to challenge it.
  • Keep external pool pricing partially independent from internal AUM publication. If a downstream Curve pool or AMM is consuming a protocol-authored exchange rate, add delayed sampling, deviation bounds, or fallback logic so one internal write cannot instantly reprice real reserves.
  • Rehearse degraded modes around valuation publication specifically: pause accounting writes, freeze exchange-rate changes, keep redemptions in bounded mode, and stop pool-oracle updates before LP liquidity becomes the monetization rail.
  • Review approved instruction libraries as oracle code, not just automation code. A Weiroll step that reads one-sided withdrawal value is effectively choosing what state can become treasury truth.
  • Model adversarial copy-trading and MEV races explicitly. If one transaction can mint or publish a profitable bad mark, assume the first visible exploit path will be backrun or copied immediately.

Audit prompts

  • Which exact instruction or helper provides Machine position value here, and is it a realizable unwind path or only a hypothetical one-sided quote?
  • Can a public user choose both the manipulated market state and the exact block when that state is published into Caliber AUM or Machine AUM?
  • What explicit control stops position read -> AUM update -> exchange-rate update -> external oracle consumption from completing atomically in one transaction?
  • If the underlying Curve pool is skewed for one block, how far can Machine exchange rate move, and what hard cap or pause condition interrupts that move?
  • Does the downstream DUSD/USDC pool treat the Machine exchange rate as immediately money-good, or is there any independent sanity check before real USDC liquidity honors it?
  • If the protocol had to exit the underlying MIM/3CRV position at the manipulated quoted value and at protocol size, could it actually do so, or is the mark only valid for a hostile one-sided spot state?
  • Which roles, keepers, or public functions are allowed to publish accounting truth, and are those lanes reviewed with the same scrutiny as explicit oracle updaters?
  • Where are publication delays, per-update bounds, or cross-checks enforced: instruction level, Caliber level, Machine level, or external pool level?
  • Could an attacker profit if the internal AUM moved but the external pool refused to consume the new mark until later? If not, the publication chain itself is the decisive exploit surface.
  • What is the protocol’s exact emergency order of operations when valuation looks wrong: freeze strategy reads, freeze exchange-rate updates, pause pool consumption, or all three?

Lessons that should already be standard

  • Accounting verbs are oracle verbs when they publish redemption or exchange-rate truth. Calling the function updateTotalAum() does not make it operationally harmless.
  • Hypothetical unwind math is not reserve truth. A one-sided exit quote from an imbalanced Curve pool should not become a protocol-wide price without strong bounding and delay.
  • Same-block composability between internal accounting and external liquidity is often the real bug multiplier. A bad read becomes a drain only when the system lets that read propagate straight into spendable market truth.
  • Permissionless bookkeeping is a governance choice about who may write price reality. If public callers can crystallize attacker-shaped state into canonical AUM, they are effectively unsupervised oracle operators.
  • Internal treasuries can remain fully backed while external LPs still get drained. That does not make the architecture safe; it means the monetization rail sat in a downstream pool rather than in the strategy vault itself.
  • MEV competition compresses response time to near zero. Once a one-transaction accounting-publication exploit exists, the relevant threat model is not one attacker but every searcher who can see mempool intent.
  • The safe boundary is not trusted internal valuation, then trusted downstream pool. It is one bounded publication layer, with time and deviation controls, before any external reserve starts honoring the new mark.

Internal linkages

Control surface

  • The decisive leverage sat in approved accounting instructions, permissionless position-value publication, same-block Caliber-to-Machine AUM propagation, and the synchronous external oracle path that fed the DUSD/USDC Curve pool.
  • Makina did not lose funds because Curve had a generic spot price. It lost funds because a hypothetical strategy unwind quote became canonical AUM, and canonical AUM immediately became tradeable pool truth.
  • The practical security lesson is that valuation publication deserves the same suspicion as oracle update. If one public verb can both observe attacker-shaped market state and publish it into redeemable or tradeable truth before the market normalizes, the protocol has effectively built its own flash-loan oracle.

Sources

Last reviewed

  • 2026-07-29 UTC