Blog · 2026-06-22 · Michael Moffett

5 billion SYS, one missing burn: Syscoin, SPV proofs, and the conservation invariant.

On June 7, 2026, the Syscoin bridge suffered a loss reported at $8.56M (rekt.news). The mechanism was a malformed SPV proof accepted as valid: approximately 5 billion SYS tokens were minted on the destination side with no corresponding burn on the source side. That is the load-bearing bug for the conservation class. The Halborn postmortem linked below covers the full exploit chain, including the precise proof fields that were malformed and the code paths that admitted them.

This post is not a postmortem. Halborn published the definitive technical incident report: proof structure, validation bypass, on-chain evidence. What this post covers is the other leg: the conservation property a bridge contract should enforce at the state-transition level, what it asserts, and how a stateful test that carries that property would have caught this class before mainnet.

What happened

Mint without burn.

SPV (Simplified Payment Verification) is a class of proof that lets one chain verify a transaction occurred on another chain without downloading the full source-chain history. Cross-chain bridges that move native tokens between chains use SPV proofs as the authorization primitive for minting: the source chain records a burn; the burn event is encoded into an SPV proof; the destination chain validates the proof and mints equivalent tokens.

The conservation property this flow should enforce is:

For every token minted on the destination, a valid proof of a corresponding burn on the source must have been accepted first.

The Syscoin bridge’s SPV validation did not hold this property under malformed inputs. A proof that should have failed validation (because the proof fields did not correspond to a real burn event on the source chain) was instead accepted. The destination contract minted approximately 5 billion SYS without a matching burn. Supply on the destination side diverged from supply on the source side. The bridge’s conservation invariant was broken.

The Nomad bridge exploit in August 2022 (~$190M) is the closest prior-art incident in this class. Nomad’s replicas stored an acceptableRoot hash used to validate bridge messages. An initialization error set acceptableRoot to 0x00. Any message with a proof rooted at 0x00, including messages with a zeroed-out or empty proof field, passed validation. The contract then processed those messages as legitimate, allowing anyone to forge claims and drain the bridge. Same pattern: proof validation admits inputs that should be rejected → tokens minted or transferred without genuine backing → conservation broken.

The specific proof field that was malformed in Syscoin’s case, and the code path that admitted it, is documented in the Halborn postmortem. This writeup stays on the invariant class.

The pattern

Supply divergence via proof validation bypass.

Cross-chain bridges in the burn-then-mint family have a core conservation invariant that spans both sides of the bridge:

total_minted_on_destination ≤ total_burned_on_source (for valid burns)

When proof validation is the gate that enforces “this burn was valid,” any bypass of proof validation is a bypass of the conservation invariant. The bridge’s correctness depends on the proof gate being sound, not merely present.

This is the pattern the conservation invariant class is built to catch: a state change (minting) that should require an authorizing condition (valid burn proof) proceeding without that condition being genuinely satisfied. The state change here is a token supply increase on the destination chain without a valid corresponding commitment on the source chain.

What the invariant asserts

The property and the violating sequence.

The property the bridge should have enforced is:

After any mint operation, the total tokens outstanding on the destination side must not exceed the total tokens proven burned on the source side via proofs that pass a sound validation.

Expressed as a stateful test property:

The violating sequence is short: craft a malformed proof, call the mint function, observe the counter diverge. A stateful fuzzer that tracks the two counters, without being told the specific malformed proof field, will find this shape by exploring the mint entry point with random proof bytes. Some random byte vectors will trigger the admitted-but-malformed path; the invariant fires when they do.

This is the same shape as the Jito claim_amount_conservation invariant in our CI-verified reference suite: total claimed must not exceed total allocated per merkle root. The merkle root is the authorization primitive for claims in Jito’s tip distribution; the SPV proof is the authorization primitive for mints in a bridge. The invariant structure is the same.

CI-verified coverage

Map to CI-verified reference pairs.

Three artifacts in the CaliperForge toolkit carry a conservation reference pair verified in CI today. All are CI-verified per agents/build_squad_lead/proof_register.md. The conservation property is rail-agnostic; the Anchor/Solana and Cairo/Starknet reference pairs are the CI-verified evidence for the class on those rails.

cf-invariants-anchor (Anchor / Solana), balance_conservation class (vault_ref / vault_ref_planted). The clean variant enforces that the vault’s token supply can only increase via calls with a valid deposit commitment; total outstanding cannot exceed total committed. The planted variant removes the supply cap check, allowing the minted/issued balance to exceed the committed backing. The conservation invariant then fires with at least one marker. Clean = 0 markers, planted ≥ 1 marker. CI-verified, commit aee4136. Repo: github.com/caliperforge/cf-invariants-anchor.

The planted vault_ref drops the commitment check before incrementing the balance. That is structurally equivalent to what the Syscoin mint function did when it accepted a proof without validating it: the branch that should gate the supply increment was bypassed. The invariant catches both by tracking the same divergence between “authorized amount” and “minted amount.”

cf-invariants-jito (Anchor / Solana), claim_amount_conservation + no_double_claim classes on the real Jito tip-distribution program. claim_amount_conservation asserts that total claimed across all recipients cannot exceed the merkle root’s total allocation. no_double_claim asserts that no recipient can receive more than their single allocation. Both planted twins remove the accounting check, allowing the invariant to fire. CI-verified at commit e683c5a. Repo: github.com/caliperforge/cf-invariants-jito.

The Jito conservation harness ran against a real on-chain program’s accounting logic, not a synthetic example. That is the framing a Syscoin-specific harness would need: instrument the real mint function’s proof-validation and supply-accounting paths → track the two-counter property → plant the validation bypass → show the invariant fires on malformed inputs.

cf-invariants (Cairo / Starknet), 12-class matrix including conservation. The 12-class reference suite covers supply conservation across ERC-20, ERC-4626, lending, staking, and vesting contracts. Each reference has a planted bug that breaks the relevant conservation property; each compile-twins to a clean variant via a clean scarb feature; each asserts planted ≥ 1 AND clean = 0 in CI. PR #2 squash-merged 2026-06-07 at commit 003e33c, CI run 27075213962 26/26 green. All twelve references deployed and source-verified on Starknet Sepolia. Repo: github.com/caliperforge/cf-invariants. Developer cookbook (public since 2026-06-11, PR #3 squash-merged at 7f94b08): github.com/caliperforge/cf-invariants/tree/main/docs/cookbook.

Harness design

What a Syscoin-specific invariant harness would look like.

The exercise is design rather than a shipped harness. Syscoin runs its own UTXO-based chain with an Ethereum-compatible execution layer (NEVM); the bridge contract lives in that EVM context. A Syscoin-specific conservation harness would target the bridge’s mint entry point in a Foundry or Hardhat test environment, not the Anchor or Cairo rails our CI-verified reference pairs use.

The invariant design is clear regardless of rail:

  1. Identify the two counters: valid_burns_proven (incremented only when SPV proof validation succeeds on a non-malformed proof) and tokens_minted (incremented on every successful mint call).
  2. Express the property: after every call to the mint entry point, tokens_minted ≤ valid_burns_proven.
  3. Test setup: include the mint function in the callspace; include a proof-generation helper that can emit both well-formed and malformed proofs. The stateful test should explore the full input space of the proof fields.
  4. Assert after every transition: if tokens_minted incremented, valid_burns_proven must have incremented by the same amount in the same call.

The violating sequence in step 4 is the exploit: mint called with a malformed proof that the validation function admits, counters diverge, invariant fires. A stateful fuzzer reaches this without being told which proof field is malformed; it only needs to know the property and the callspace.

The design above is a reference for teams building conservation harnesses against bridge contracts in the EVM context.

Sources

Primary analysis and CaliperForge artifacts.

Prior-art reference:

CaliperForge artifacts cited:

Operator of record: Michael Moffett , michael@caliperforge.com , team@caliperforge.com. This writeup was drafted with AI assistance; the invariant framing, the coverage mapping, and this post were all reviewed by the operator. See caliperforge.com/ai-disclosure for the full disclosure register.