State-Publication Authority Failure / Accounting Canonicalization Abuse

  • Name: state-publication authority failure / accounting canonicalization abuse
  • Category: exploit pattern / accounting-publication failure / attacker-timed canonicalization / sync-harvest-cache-write abuse / protocol-authored accounting truth failure
  • Summary: This exploit family appears when a protocol has some intermediate accounting state that is not yet supposed to be money truth — pending rewards, a fresh exchange rate, a harvested profit figure, a cached NAV, a reserve refresh, or a newly recognized wrapper balance — and then exposes a helper that can bless that state as canonical. The attacker does not always need to forge balances or falsify an external oracle. Often they only need to shape an intermediate condition, then choose the exact moment a function like syncRewards(), harvest(), cacheAssetPrice(), _updateDebtAndCollateralIndex(), gulp(), or some equivalent publication helper turns that condition into official share value, debt relief, collateral value, or reserve truth. Once that write lands, downstream mint, withdraw, redeem, borrow, or debt-accounting logic stops seeing tentative state and starts seeing the protocol's own answer.
  • Fast routing: start with Alchemix alETH when wrong-vault harvest logic publishes false profit as borrower debt repayment; GoGoPool when donated WAVAX only becomes next-depositor pricing truth after syncRewards(); Zunami when a strategy-side donation plus thin-market mark only becomes token-balance truth after cacheAssetPrice(); Raft when a donation only becomes borrowable collateral once _updateDebtAndCollateralIndex() republishes raw balance growth into canonical collateral-index truth; Balancer STA when stale reserve drift only becomes live drainable pricing after gulp() collapses internal reserves to attacker-shaped dust reality; ResupplyFi when a fresh wrapper mark only becomes exploitable once reciprocal conversion logic crystallizes it into canonical exchangeRate state; and KiloEx when a weakly authenticated forwarder / keeper chain lets the attacker self-publish absurd internal mark prices as protocol-owned truth without moving any external market first.
  • What it is:
    • The protocol has some candidate accounting state that is not yet supposed to be final economic truth.
    • A helper function can publish that candidate state into canonical storage, canonical reserves, a canonical share price, or a canonical debt / collateral index.
    • The system treats that helper as bookkeeping or liveness plumbing instead of as a solvency-boundary authority surface.
    • The attacker first shapes or times the candidate state, then triggers the publication step at the most favorable moment.
    • Downstream consumers immediately trust the published result as if it were fully settled, honest protocol truth.
  • Typical preconditions:
    • One or more public or weakly bounded helpers can convert observed or inferred state into canonical accounting state.
    • The candidate state depends on something attacker-timable or protocol-misclassified: a donation, stale reserve drift, a thin-market mark, a wrong vault pointer, a fresh wrapper rate, or a module-local accounting disagreement.
    • Publication can happen in the same block or same transaction as monetization.
    • Downstream consumers do not distinguish freshly published from settled and trustworthy; they immediately use the result for minting, redemption, collateral valuation, debt forgiveness, or pool pricing.
    • One publication step can move enough value that the attacker can cash out before human operators or slower controls react.
  • Common vulnerable surfaces:
    • vault and wrapper helpers such as syncRewards(), harvest(), checkpoint(), cacheAssetPrice(), updateIndex(), and reserve-refresh paths
    • debt or collateral index publishers that treat freshly recognized balance growth as canonical solvency truth
    • AMM helpers like gulp() or related reserve-sync routines that turn latent reserve drift into live pricing truth
    • strategy, AUM, or share-price writers that can publish a manipulable unwind quote or transient mark into canonical exchange-rate state
    • any path where the same actor can both shape candidate state and trigger the helper that canonizes it
  • Exploit sequence:
    1. The attacker identifies a helper that writes accounting state other modules later trust as canonical.
    2. They find a way to shape the candidate input: donation, stale accounting drift, thin-market trade, wrong module selection, or some other transient but monetizable condition.
    3. They hold that manipulated or misclassified state live for one block, one transaction, or one accounting frame.
    4. They trigger the publication helper so the protocol itself stores or refreshes the attacker-shaped value.
    5. A mint, redeem, withdraw, borrow, liquidation, or debt-relief path immediately consumes the newly published value as if it were honest settled truth.
    6. The attacker exits against real assets, real borrow capacity, or real debt forgiveness before the state can be corrected.
  • Variants:
    • Harvest profit misclassification — modules disagree about which vault, deposit set, or denominator is canonical, and harvest() publishes false profit that the system honors as debt repayment or share growth. Alchemix alETH is the clean exemplar.
    • Reward-sync publication — a donation or pending reward balance only becomes share-pricing truth after a sync helper recognizes it. GoGoPool is the clean bootstrap exemplar.
    • Cached-NAV snapshot abuse — a transient strategy-side valuation gets frozen into a cached price, index, or exchange rate that remains live long enough to monetize. Zunami is the clean accounting-side exemplar.
    • Collateral-index republication — raw contract-balance growth or a fresh wrapper mark only becomes borrowable because an index-update path republishes it into canonical collateral truth. Raft and ResupplyFi are strong exemplars on that seam.
    • Reserve-refresh collapse — stale internal reserve accounting is already wrong, but a public refresh like gulp() decides exactly when that wrongness becomes active pricing and redemption truth. Balancer STA is the clean exemplar.
    • Same-transaction accounting relay — a manipulable valuation or fresh wrapper mark becomes canonical accounting truth and reaches a money-moving consumer in the same transaction.
  • Quick classifier:
    • If the main question is who was allowed to make this attacker-shaped intermediate accounting state canonical right now?, start here.
    • If the main question is how was the exchange rate or share price inflated in the first place?, start with donation-share-price-manipulation or first-deposit-inflation and return here for the publication step.
    • If the main question is what exact helper let a stale, donated, or wrong-vault value become official protocol truth?, stay here.
    • If the main question is why did a protocol-authored local reserve or pool state behave like an oracle?, compare with protocol-authored-market-state-oracle-failure. Use that note when the pricing object itself is the analytical center; use this one when the sharper lesson is the sync / harvest / cache helper that made the object canonical.
    • If the main question is broader design hardening rather than exploit classification, move to sync-harvest-and-cache-write-authority-discipline.

Three accounting-publication promotions reviewers should not collapse

  1. Fragile candidate accounting state exists

    • A donation, pending reward delta, stale reserve drift, wrong vault pointer, thin-market wrapper mark, or fresh balance change is visible somewhere in the system.
    • This is only an observation fact. It still does not answer who may bless that state as canonical accounting truth or which downstream consumers deserve to trust it.
  2. Canonical local accounting publication exists

    • A helper such as syncRewards(), harvest(), cacheAssetPrice(), updateIndex(), _updateDebtAndCollateralIndex(), or gulp() writes that candidate state into canonical storage, canonical reserve accounting, canonical debt relief, or canonical share / collateral / NAV state.
    • This is already a much stronger authority step than merely noticing the value. But it is still not automatically proof that every downstream mint, redeem, borrow, or debt-accounting consumer should honor the freshest possible publication right away.
  3. Economically active downstream accounting truth exists

    • Mint, burn, redeem, withdraw, borrow, liquidate, forgive debt, or pool-pricing code is now allowed to spend against the freshly published accounting state.
    • This deserves its own boundary too. Published now is often not yet the same thing as safe to honor everywhere right now.

The recurring reviewer task is to answer three separate questions cleanly: what fragile accounting state was visible?, what exact helper published it as canonical local truth?, and which consumers were actually entitled to trust that fresh publication immediately?

  • Detection heuristics:
    • Search for functions named sync, harvest, checkpoint, cache, gulp, updateIndex, updateAum, or similar and ask what exact economic truth they are allowed to publish.
    • Ask whether the same actor can both move the candidate state and trigger the helper that records it.
    • Look for same-block or same-transaction paths where published state is immediately consumed by mint, redeem, borrow, withdrawal, liquidation, or swap logic.
    • Review whether the helper publishes state derived from donations, thin markets, stale reserves, wrong module pointers, or module-local bookkeeping that can still be wrong.
    • Test whether normalizing the manipulated market state after publication still leaves the protocol exploitable because the cached or stored value survives long enough to matter.
    • Treat permissionless publication as a real security decision. If public publication is safe, the code should show explicit bounds, delays, smoothing, or downstream distrust.
  • Defenses:
    • Model sync, harvest, cache-write, reserve-refresh, and index-update helpers as accounting-oracle publishers, not harmless housekeeping.
    • Separate observation from publication and publication from activation; a newly written value should not automatically become same-block redemption, collateral, debt, or reserve truth.
    • Bound per-call impact with deviation caps, monotonicity rules, cooldowns, and per-epoch movement limits.
    • Make downstream consumers distrust freshly published values until a delay, amortization window, or independent check makes them safe to honor.
    • Keep internal topology canonical before publication. Wrong vault pointers, stale denominators, and stale module relationships should never become publishable profit or collateral truth.
    • Add adversarial tests that explicitly combine shape state -> publish state -> monetize state in one transaction.

Failure-prevention checklist

  • Inventory every function that can turn candidate state into canonical accounting truth: sync, harvest, checkpoint, cache, gulp, reserve refresh, index updates, collateral-index writes, reward recognition, and cached-NAV publication. Treat that inventory as solvency-boundary code.
  • For each publisher, write down what candidate input it is allowed to crystallize and how an attacker could shape that input: donation, thin-market quote, stale reserve drift, wrong vault pointer, delayed reward, fresh wrapper mark, or module-local accounting disagreement.
  • Split observation, publication, and activation into separate stages whenever possible. A value being writable to storage should not automatically make it same-block redemption, collateral, debt-forgiveness, or swap-pricing truth.
  • Inventory downstream consumers for each publication helper, not just the helper itself. Review exactly which redemption paths, debt-relief flows, collateral engines, reserve-pricing rails, or vault-share mint / burn surfaces will trust the freshly published value.
  • Put hard movement limits on one publication step: deviation caps, monotonicity guards, epoch limits, or capped amortization. If one call can move too much truth, the helper is over-authorized.
  • Preserve an explicit gate from canonical local accounting publication to economically active downstream accounting truth; one helper should not silently promote a fragile value through both steps unless the protocol can defend that full combined transition.
  • Prevent the same actor from both shaping candidate state and immediately publishing it into canonical storage unless the downstream effect is tightly bounded.
  • Require downstream consumers to distinguish freshly published from settled. Lending, liquidation, withdrawal, and reserve-paying paths should be able to quarantine, haircut, delay, or ignore just-written values.
  • Keep module topology canonical before publication. Vault pointers, strategy registries, reserve ledgers, denominator state, and collateral adapters should not be mutable enough that a later helper can publish fiction from the wrong object.
  • Adversarially test one-transaction bundles that do manipulate -> publish -> monetize -> normalize. If the exploit still pays after the market leg is unwound but the published state remains live, the publication boundary is too weak.
  • Monitor for publication-risk signals in production: outsized one-call rate jumps, unusual sync timing after donations, same-block cache updates followed by large redemptions or borrows, and debt or collateral indices moving much faster than plausible organic growth.
  • Make rollback explicit. If a bad publication lands, the protocol should know which consumers can be paused, which caches can be invalidated, and how blast radius is capped before governance catches up.

Audit prompts

  • Which exact functions are allowed to convert candidate accounting state into canonical state, and what downstream code immediately trusts their output?
  • Can one actor both create the favorable state and choose the publication moment in the same transaction or block?
  • What manipulative inputs feed the publisher: donations, stale reserves, thin-market valuations, reward deltas, wrong module selection, or fresh wrapper marks?
  • Does publication itself have effect bounds, or is the real safety assumption merely nobody will time this adversarially?
  • Which downstream consumers treat a freshly published value as live truth for minting, redeeming, borrowing, withdrawing, liquidating, debt relief, or pool pricing without an extra distrust boundary?
  • If the manipulated state normalizes right after publication, does the protocol still lose because the cached or stored value survives long enough to be monetized?
  • Are there helpers that look operational — harvest, sync, gulp, cache, checkpoint, updateIndex — but in practice exercise authority over solvency or reserve truth?
  • Can stale or wrong module topology make honest-looking publication code write dishonest economic truth, as in wrong-vault harvest or bad denominator selection?
  • What exactly prevents observe bad state -> publish bad state -> spend against bad state from happening in one attacker-controlled bundle?
  • When a publication is later found unsafe, how is it contained: invalidation bit, cooldown, stale flag, pause, bounded per-asset loss cap, or nothing?

Lessons that should already be standard

  • It only updates a cache is not a defense. If later code trusts the cache for money movement, the cache writer is an oracle publisher.

  • Timing rights are economic rights. Public housekeeping is still authority when the caller chooses when fragile state becomes canonical.

  • A protocol’s own published answer is often more dangerous than the raw manipulation that preceded it, because every downstream module tends to trust protocol-authored storage more than a visibly noisy market state.

  • Fragile candidate accounting state, canonical local accounting publication, and economically active downstream accounting truth are different trust levels. The safest design often lets the system notice fresh state quickly, publish it narrowly, and force money-moving consumers to accept it only later or only in bounded form.

  • Same-block publication plus same-block monetization is the recurring catastrophe shape. If the protocol cannot defend that bundle, it should break the bundle.

  • Sync and harvest code deserve the same adversarial review as mint, burn, borrow, and liquidation code. In this family, the helper is the monetization boundary.

  • Wrong internal topology is as dangerous as wrong prices. A harvest against the wrong vault or an index update against the wrong object can publish fiction without any external market manipulation at all.

  • The durable question is not just can this value be manipulated? but who is allowed to bless it as real, with what effect, and how quickly do other modules believe them?

  • High-signal incidents:

  • Why this pattern matters:

    • Security reviews often notice the bad candidate input but underweight the helper that makes it canonical. The publication helper is frequently the monetization multiplier.
    • This pattern explains why incidents that initially look unrelated — donations, rollout mistakes, stale reserves, fresh wrapper marks, cached strategy prices — rhyme at the decisive moment where a helper blesses bad intermediate state into official accounting truth.
    • It is the accounting-family reminder that a protocol’s own authored write can be more dangerous than the external manipulation that preceded it, because every downstream consumer is inclined to trust storage written by us more than market state observed by us.

What sound design looks like

  • One observation boundary should stay explicit: a protocol may notice donations, pending rewards, stale reserve deltas, wrong-vault output, thin-market wrapper marks, or fresh balance changes without yet treating them as money-good accounting truth.
  • One publication boundary should be explicit: helpers that write reserves, NAV, rewards, debt relief, collateral indices, or share-value state should be treated as accounting-oracle publishers with narrowly defined authority, not as passive bookkeeping.
  • One activation boundary should stay separate from publication: a freshly written accounting value should not automatically become immediate solvency, withdrawal, redemption, debt-forgiveness, or reserve-pricing truth without delay, smoothing, quarantine, or independent confirmation.
  • One actor should not control the whole shape -> publish -> monetize bundle. The cleaner design separates who can influence candidate accounting state, who can publish it, and who can spend against it.
  • One publication step should have bounded blast radius: deviation caps, epoch caps, monotonicity rules, or amortized updates should keep a single cache write or sync call from rewriting too much economic truth at once.
  • One bad publication should be containable: caches should be invalidatable, downstream consumers pausable, and just-published values quarantineable before they cascade into systemwide loss.

Where this pattern stops

  • Use donation-share-price-manipulation when the main analytical work is how the attacker printed or inflated the wrapper rate itself.
  • Use first-deposit-inflation when the main lesson is zero-supply bootstrap capture rather than attacker-timed publication of already-shaped state.
  • Use reward-index-initialization-failure when the decisive mistake is not publication timing but a flywheel’s own sentinel and initialization semantics.
  • Use balance-delta-provenance-failure when the deeper failure is that a raw balance change was misread as the wrong economic event before any publication-helper question appears.
  • Use state-publication authority failure when the sharper lesson lives in explicit price publication, market-state oracle behavior, or off-family oracle-writing surfaces rather than in accounting, issuance, reward, debt, or share-state canonicalization. KiloEx is the clean cross-family exemplar there: the decisive publication helper was an attacker-reachable oracle write path rather than an accounting sync or share-state canonicalization helper.

Internal linkages

  • Positive-design companion: sync-harvest-and-cache-write-authority-discipline — this note classifies the failure family; that note is the design checklist for how publication authority should have been bounded.
  • Adjacent pattern: donation-share-price-manipulation — use that note when the exchange-rate lie itself is the analytical center and this one when the sharper follow-up is who was allowed to crystallize that lie into canonical accounting truth.
  • Adjacent pattern: first-deposit-inflation — GoGoPool sits on the seam where first-depositor capture becomes much worse because reward publication is attacker-timed.
  • Adjacent pattern: balance-delta-provenance-failure — some incidents combine what balance growth meant confusion with who could publish it confusion.
  • Adjacent pattern: reward-index-initialization-failure — useful contrast when the exploit comes from inconsistent initialization semantics rather than attacker-timed publication of otherwise-valid candidate state.
  • Adjacent oracle cousin: state-publication-authority-failure — same structural control surface, but the oracle-market-abuse note is the better home when the pricing object or oracle-writer boundary itself is the main preserved lesson. KiloEx is the sharp current cross-family exemplar for that branch.
  • Best concrete routing cluster so far: Alchemix alETH for harvest profit misclassification, GoGoPool for reward-sync publication, Zunami for cached-NAV snapshot abuse, Raft Finance and ResupplyFi for collateral-index / exchange-rate publication, and Balancer STA for reserve-refresh collapse.

Control surface