Bootstrap-State Replay / Reversible Initialization Semantics

  • Name: bootstrap-state replay / reversible initialization semantics
  • Category: exploit pattern / low-supply lifecycle failure / bootstrap replay / share-accounting exploit
  • Summary: This pattern appears when a live system decides we are in pristine bootstrap state again from reversible runtime variables such as totalSupply == 0, prev_supply == 0, empty reserves, or another dust-state condition. An attacker first drives the system back toward that state — or manufactures an equivalent one — and then re-enters launch-only mint, pricing, or rate-initialization logic that should have been permanently one-way. The exploit is not merely first deposit is dangerous; it is that production can accidentally become new again and reopen initialization semantics under adversarial control.
  • What it is:
    • A vault, pool, wrapper, or reserve system has special bootstrap logic meant only for first launch.
    • The system later infers bootstrap is active from economic state instead of an irreversible control fact.
    • An attacker drives live state back toward zero supply, empty reserves, or another launch-like configuration, often after first corrupting or draining the system.
    • Once the bootstrap branch is reachable again, launch-only assumptions about mint math, rate setting, supply bounds, or ownership concentration become exploitable in production.
    • The payout comes from whatever that reopened branch can now do: infinite minting, fresh exchange-rate capture, next-depositor theft, or downstream borrowing against a newly printed rate.
  • Typical preconditions:
    • The code keys launch-only behavior off reversible variables like totalSupply == 0, prev_supply == 0, an empty reserve book, or another runtime quantity that adversaries can revisit.
    • No irreversible initialized fact, consumed bootstrap object, or explicit recovery mode separates first launch from low-supply production state.
    • The system can plausibly be driven toward dust supply through withdrawals, loss socialization, POL reconciliation, market drains, or other ordinary runtime paths.
    • A bootstrap branch still carries privileged economic behavior: special mint formulas, different invariant assumptions, relaxed bounds, or opening-rate authority.
    • Downstream modules or sibling pools still honor the resulting claims, balances, or exchange rate as real value.
  • Common vulnerable surfaces:
    • share systems whose first deposit or first mint branch can reactivate after supply decays toward zero
    • weighted pools or stableswap-like systems that reopen initialization-only solver logic once internal supply reaches 0
    • vaults that assume empty means safe to define a new capitalization table
    • products with protocol-owned liquidity, residual shares, or dual-supply accounting that can make internal supply == 0 reachable without a clean restart
    • recovery or recapitalization flows that are not explicit control states and instead piggyback on ordinary deposit semantics
  • Exploit sequence:
    1. The attacker identifies a live system whose bootstrap or first-deposit semantics are keyed off reversible economic state rather than an irreversible initialization fact.
    2. They push the system back toward that state, often by draining liquidity, burning or socializing supply, or otherwise collapsing the normal production capitalization table.
    3. The target now satisfies a launch-like predicate such as prev_supply == 0 or totalSupply == 0 even though it is still a live production system.
    4. The attacker enters the reopened bootstrap branch with a dust-sized or carefully shaped position.
    5. The launch-only math or assumptions now run in a context they were never meant to face: residual balances, prior invariant damage, stale accounting, or adversarially chosen low-supply state.
    6. The branch mints excessive claims, assigns the next capitalization table incorrectly, or publishes a fresh but attacker-controlled rate.
    7. The attacker cashes those claims out through direct redemption, a sibling pool, collateral borrowing, or the next depositor.
  • Variants:
    • Near-zero-supply replay — a live share system burns or drains down to dust, so first-depositor economics come back without a redeploy.
    • Zero-internal-supply replay — a system with internal supply distinct from token supply can reach internal supply == 0 while other balances still exist, reopening initialization math on top of dirty state.
    • Recovery-impersonates-bootstrap — recapitalization or treasury repair silently reuses ordinary deposit semantics, letting whoever arrives first after damage define the repaired capitalization table.
    • Bootstrap-to-collateral replay — the reopened branch does not directly steal from the next depositor; it prints a fresh rate or supply value that a sibling lending market later honors.
  • Boundary tests that keep this pattern distinct:
    • Classify it here when the sharpest lesson is that a live system could become new again because lifecycle state was inferred from reversible economic state. If the incident mostly teaches bootstrap should have been one-way, this note should do the analytical work.
    • Classify it under first-deposit inflation when the main theft is still the classic next depositor gets zero or negligible shares launch-state attack and no production replay is needed.
    • Classify it under share-price manipulation when the interesting part is mainly how an inflated rate becomes borrowable or spendable truth, even if a low-supply replay helped set the stage.
    • Classify it under fresh-market initialization failure when the exploit comes from unsafe first activation of a new lending market or reserve rather than a previously live system returning to launch semantics.
    • Do not widen this into generic constructor or proxy initialization bugs. Ownership-takeover initialize() flaws belong under re-initialization ownership takeover; this note is about economic bootstrap state in live share or reserve systems.
  • Detection heuristics:
    • Search for launch-only branches gated by totalSupply == 0, prev_supply == 0, supply == 0, empty reserve checks, or similar reversible runtime conditions.
    • Ask whether those predicates can become true again after withdrawals, burns, emergency exits, POL reconciliation, migrations, or invariant damage.
    • Trace what special authority the bootstrap branch gets: different pricing equations, unchecked math, relaxed bounds, id resets, or opening-rate control.
    • Simulate adversarial low-supply recovery, not just deployment-day first deposit.
    • Treat the pool is empty again as a dangerous runtime mode rather than evidence that ordinary bootstrap code is safe to reuse.
    • For systems with dual accounting layers, test internal supply == 0 separately from ERC-20 totalSupply == 0; exploitable replay often lives in that mismatch.
  • Defenses:
    • Make bootstrap an irreversible control fact, not an inference from runtime economic state.
    • Permanently disable or strongly gate launch-only mint and pricing branches after first initialization.
    • If low-supply recovery is a real operational possibility, use an explicit recovery or recapitalization mode rather than ordinary deposit semantics.
    • Maintain non-redeemable floors, virtual offsets, or other mechanisms that stop one dust holder from redefining the capitalization table after damage.
    • Quarantine low-supply or post-repair rates before presentation layers, redemption paths, or collateral adapters trust them.
    • Re-test bootstrap assumptions after any feature that can shrink supply dramatically: POL burns, reward-writeoff flows, migration helpers, emergency exits, and partial drain recovery.

Three lifecycle promotions reviewers should not collapse

  1. A live system returned to low-supply, zero-supply, or otherwise launch-like runtime state

    • totalSupply == 0, prev_supply == 0, empty reserves, or another degenerate balance-sheet condition may be true again.
    • That only proves production has become bootstrap-shaped, not that bootstrap authority has legitimately reopened.
  2. The protocol promoted that runtime state into canonical bootstrap is active truth for one exact branch

    • A first-mint solver, opening-rate path, recapitalization shortcut, or special ownership table now treats the live system as if it were pristine first launch.
    • This is already a much stronger claim than supply got small again, because it says one adversarially reachable runtime condition still counts as lifecycle truth.
  3. Claims or rates authored under that accepted bootstrap story still deserved live monetary authority

    • The branch can now mint shares, define a new capitalization table, publish a fresh exchange rate, or produce output that redemption, collateral, AMM, or UI-facing systems will honor.
    • This is the last and most expensive promotion: a launch-like accounting answer becomes money-good production authority.

Healthy review keeps those steps separate. The pool is empty again, the code therefore treated it as a new pool, and the resulting claims/rates were allowed to move money are not one fact. This branch stays much easier to miss when teams collapse them into one comforting sentence like bootstrap math only matters when supply is zero anyway, because the real question is whether zero-like runtime state had actually earned the right to reactivate one-time lifecycle semantics.

What sound design looks like

  • A healthy system can only be born once. First launch, production, and damaged / recapitalizing are distinct lifecycle states, and only an explicit one-way transition may leave bootstrap. Bootstrap-state irreversibility and supply-floor design is the narrower positive-design companion for making that one-way transition real rather than inferred.
  • Low-supply production is treated as degraded mode, not as a second genesis. If supply collapses, reserves empty, or invariant math becomes delicate, the protocol should narrow authority, quarantine pricing, and require deliberate recapitalization policy before ordinary user deposits can matter again. Low-supply recovery and recapitalization discipline is the companion for that damaged but still live state.
  • Bootstrap-only math should consume a bootstrap-only object. Opening-rate setters, first-mint solvers, and first-share distributions should not remain latent capabilities that a live balance sheet can accidentally reactivate by drifting toward zero.
  • Supply floors, virtual offsets, dead shares, or equivalent anchors should be sized and governed as lifecycle controls, not just as rounding conveniences. Their job is to keep nobody meaningful left from becoming whoever arrives next owns the capitalization table.
  • Repair and publication must stay separate. A healthy protocol can reconcile balances, socialize losses, or reseed reserves without immediately publishing a fresh spendable or borrowable rate to redemptions, collateral adapters, or UI-facing share-price surfaces.
  • The clean reviewer question is: if this system is half-dead, dusty, or recapitalizing, what exact irreversible fact still prevents ordinary user flow from re-entering first-deposit economics?

Failure-prevention checklist

  • Encode lifecycle state explicitly. bootstrap complete, recovery required, and production active should be durable control states, not conclusions reconstructed from totalSupply, empty balances, or a solver denominator landing at zero.
  • Treat any path that can shrink effective supply toward zero as security-critical: redemptions, loss socialization, protocol-owned-liquidity burn-down, emergency exits, migration drains, write-offs, and invariant-repair flows all need the same review as the original first-deposit path.
  • Make low-supply recovery a different code path from ordinary deposits. If the protocol truly needs recapitalization after damage, require explicit operator intent, reseeding, and post-repair checks before new deposits can define pricing again.
  • Keep a non-redeemable floor, virtual offset, dead shares, or equivalent supply anchor large enough that no dust holder can cheaply become the whole capitalization table after partial drain or cleanup.
  • Rehearse state-machine edges, not just formula edges: test live -> damaged -> near zero -> repaired -> live again and assert that no step re-enables constructor-era pricing or mint semantics.
  • Bind bootstrap-only math to bootstrap-only objects. If an initialization solver, first-rate setter, or opening-weights path exists, it should be unreachable once the initial object is consumed.
  • Separate accounting repair from economic publication. A helper that reconciles balances, refreshes rates, or repairs an invariant should not simultaneously make a post-damage rate immediately redeemable or borrowable.
  • Add monitoring for production-impossible lifecycle reversions: prev_supply == 0 after launch, reserve books that become empty while wrappers stay live, or recapitalization events happening through ordinary user verbs.
  • Put blast-radius limits under the lifecycle boundary anyway: caps, collateral quarantine, pause paths, and borrow-side disablement should stop one reopened bootstrap branch from draining healthier sibling systems.
  • Audit protocol-owned-liquidity and treasury buffers as part of the same model. If the system can socialize attacker-created accounting gaps into POL before bootstrap replay occurs, the attacker may be able to buy the reset state with someone else’s balance sheet.

Audit prompts

  • What exact predicate tells the code we are in bootstrap today, and can any live runtime path make that predicate true again after deployment?
  • Which functions can reduce economic or internal supply toward zero without an explicit redeploy: redeem, burn, migration, emergency exit, loss absorption, rate-repair, or POL reconciliation?
  • Does the system distinguish economically empty, mathematically degenerate, and authorized to run first-deposit math again, or are those still collapsed into one branch?
  • If internal supply and token supply differ, which one gates initialization logic, and can they diverge under stress or partial cleanup?
  • When the system is damaged or recapitalized, what path republishes a usable rate, share price, invariant, or opening weight — and does that publication require deliberate recovery authorization or only an ordinary user interaction?
  • Are there helper functions whose stated purpose is repair, sync, or cleanup but whose actual effect is to move the protocol into a launch-like pricing regime?
  • If a bootstrap branch were accidentally reachable again, what downstream modules would immediately trust the resulting claims: redemption, sibling lending markets, AMM exits, liquidation engines, or reward distributors?
  • What invariant proves that first-deposit economics can only happen once rather than whenever supply becomes small enough again?
  • Which post-incident or post-migration playbooks assume humans will reseed, pause, or reconfigure things in the right order, and where is that sequencing enforced in code instead of process?
  • Can the attacker externalize the cost of getting back to bootstrap-like state into protocol-owned liquidity, treasury inventory, or other users before cashing out the reopened branch?

Lessons that should already be standard

  • Supply is zero again is an accounting observation, not permission to pretend history never happened.

  • Bootstrap is a one-way lifecycle event unless governance deliberately creates a new one. If code can silently infer bootstrap from runtime balances, the protocol has left a hidden restart button on-chain.

  • Repairing a broken invariant and authorizing fresh capitalization are different jobs. Combining them in one ordinary user path turns incident recovery into an exploit surface.

  • Near-zero supply is not harmless cleanup state. It is concentrated control over rate-setting, ownership, and future dilution.

  • Protocol-owned liquidity makes lifecycle bugs worse when it can absorb attacker-created losses on the way to a reset state. POL is not just a stabilizer; it can become bootstrap fuel.

  • We only use this branch at launch is not a defense unless the state machine makes it impossible to reach later.

  • Any product that can be drained, partially socialized, or recapped should be reviewed as if attackers will try to manufacture a second genesis.

  • Lifecycle state belongs inside the same security boundary as invariant math, reserve accounting, and collateral admission. Treating them as separate concerns is exactly how live systems become new again under hostile conditions.

  • High-signal incidents:

    • infinite-mint exploit (2025-11-30) — the clearest preserved exemplar: the attacker first drove the live pool’s internal supply back to 0, then re-entered an initialization-only branch with a 16 wei dust deposit and minted effectively infinite yETH LP.
    • GoGoPool ggAVAX first-depositor share-price inflation near miss (2023-01-03) — not a full replay incident, but the cleanest contrast case for why launch-state assumptions are dangerous in the first place and why systems should never allow production to revisit economically equivalent dust-supply conditions.
    • zero-share victimization preserves the pure launch-state cousin where the attacker does not need to rewind a live system; they only need to win the first-depositor race.
  • Why this pattern matters:

    • It preserves a lifecycle lesson that ordinary first-deposit and donation notes only partly capture: bootstrap risk is not confined to deployment if runtime accounting can revisit launch-like states.
    • It also forces a more precise security boundary. Supply reached zero is an economic fact; bootstrap is allowed again is a governance and lifecycle fact. Those must not be the same thing.
    • The pattern is especially useful for reviewing systems with protocol-owned liquidity, dual-supply accounting, or bespoke invariant solvers, because those designs are exactly where still live and looks empty can diverge.

Internal linkages

Control surface