On 6 September 2026, roughly 3,996 bitcoin walked out of a Bitcoin sidechain. No key was stolen. No curve was broken. A lookup table said a proof had already been checked, so nobody checked it.
On 6 September 2026, about 3,996 BTC — roughly $320 million — left the Liquid Federation wallet after a customer submitted 4,000 L-BTC to SideSwap's peg-out service. Liquid hides transaction amounts, so every output must carry a range proof showing the hidden number is not secretly enormous. Because that check is expensive, nodes cache the result and reuse it. Independent analysis of the Elements source indicates the cache key omitted asset and script context, so a result recorded for one validation was reused for a different one where it did not apply. An output that should have been rejected was accepted without ever being checked, minting L-BTC that no bitcoin backed. Section 04 lets you build that counterfeit yourself, section 05 shows the cache key that let it through, and section 07 separates what is confirmed from what is not.
If no key was stolen and no signature was forged, how does $320 million leave a vault that eleven institutions have to agree to open?
It leaves because everyone involved followed the rules correctly. That is the unsettling part.
Liquid is a Bitcoin sidechain run by a federation: a group of known institutions jointly custody the bitcoin that backs L-BTC, and a peg-out is the ordinary process of handing back L-BTC to get real bitcoin out. On 6 September, that process ran exactly as designed.
No step in that sequence involves breaking anything. The failure is entirely upstream, in step one, in a question no human ever looked at: was this output's amount actually checked?
To see why that question is the whole ballgame, you need to see what a Liquid transaction looks like to the network. Which is: almost nothing.
One of these four payments is hundreds of times larger than the others. Which one?
Below are four real Liquid-style outputs. Each is a commitment: a point on the same elliptic curve Bitcoin uses, computed from the amount and a large random blinding factor. This is exactly what a Liquid node has to work with.
Pick the big one. Then check.
Guessing gets you 25%, and no amount of staring improves on it. The blinding factor is doing its job: the same amount produces a completely different point every time it is committed, and any point could be hiding any number.
Which raises the obvious problem. If a node cannot read the amounts, how can it tell whether a transaction is honest?
Three transactions arrive. You can see the commitments and nothing else. Which do you accept?
Commitments have a property that sounds impossible: the commitment to a sum equals the sum of the commitments. So you can add up every input, subtract every output, and see whether the result comes out to zero — without ever learning a single amount.
That is the entire balance check. Run it three times below. Each transaction is computed live; you see precisely what a node sees.
The first two are what the balance check is for. The third is the problem, and it is worth being precise about why: that transaction did not sneak past the check. It passed. The commitments cancel to an exact zero. There is nothing in the arithmetic for a verifier to object to.
How can a transaction create money from nothing and still balance to zero?
Because curve arithmetic wraps around. There is a largest number — the curve order, a 78-digit value written n — and counting past it starts again from zero, the way a clock goes from 12 back to 1.
Below, the attacker owns 1 L-BTC and wants to walk away with 3,996. Set the two output amounts to anything you like. Two independent checks run live on whatever you type.
Press Try −3995 and watch what happens. There are no negative amounts on this curve — a negative number is silently the same thing as an enormous positive one. The value committed to is 78 digits long, and it is exactly the value the balance check needs in order to cancel.
Keep pushing and the two lights never both go green while money is being created. That is not luck, it is the theorem the whole system rests on: if a transaction balances and every output is inside the range, then nothing was created. The range proof is not a nice-to-have bolted onto the balance check. It is the half that makes the other half mean anything.
Which is why the interesting question is not how the maths works. It is how a node ends up not running it.
If range proofs are the one thing standing between a sidechain and infinite money, why would any node skip one?
Nobody set out to skip one. They set out to avoid doing the same work twice.
Range proofs are the most expensive thing in a confidential transaction — the reason Liquid transactions are larger and costlier to validate than equivalent Bitcoin ones. And a node verifies the same proof more than once: when the transaction arrives in the mempool, and again when it appears inside a block.
So nodes cache the result. Verify a proof, write down the answer, reuse it if the same proof turns up again. This is completely standard. Bitcoin Core caches signature and script validation for the same reason, and has for years. Its script cache key deliberately includes the validation flags, because the same script under different flags is a different question.
Independent analysis of the Elements source published after the incident indicates that Liquid's range-proof cache key omitted asset and script context. Two validations that differed in ways that mattered produced the same label. Edit the fields below and watch what each kind of key does.
Both keys are real SHA-256 digests, computed in your browser from the fields above.
That split in the last two boxes is what the network actually experienced. The nodes producing blocks accepted the transaction; others, including those behind mempool's Liquid explorer, rejected the affected block. An explorer following the rejecting nodes would simply not show transactions that existed elsewhere.
After that, no cleverness was required. The counterfeit L-BTC went through the peg-out service like any other coin, and roughly 3,996 BTC came out the other side.
Is this a sidechain problem, or something older?
Older. And the first time, it was the same wrap-around you just triggered by typing a negative number.
15 August 2010. A transaction in block 74638 carried two outputs of roughly 92.2 billion BTC each. Bitcoin checked, correctly, that outputs did not exceed inputs. But the two enormous values summed past the ceiling of a 64-bit integer and wrapped around, so the total the check examined was tiny. The check passed. 184.467 billion BTC existed for about five hours before a patched client and a chain reorganisation erased it.
A balance check working exactly as written, defeated by arithmetic that wrapped. Sixteen years later, on a different chain, in a different number field, the same shape.
September 2018. CVE-2018-17144 let anyone inflate the supply using duplicate inputs. The check that would have caught it had been removed from Bitcoin Core in an earlier release — as a performance optimisation. It sat in shipped code for roughly two years before disclosure. Nobody exploited it.
Three incidents, one lesson, and it is not "confidential transactions are dangerous" or "sidechains are dangerous." It is this: the checks that get skipped are the expensive ones, and the expensive ones are expensive because they are load-bearing. Performance work near consensus code is where money goes to disappear.
How much of the above should you actually believe today?
The movement of funds is documented. The mechanism is a well-supported reconstruction by people reading the Elements source and the disputed blocks. The chain of events that put that code into production is, so far, an unverified account.
| Claim | Status |
|---|---|
| ~3,996 BTC left the federation wallet on 6 Sept | Documented |
| 4,000 L-BTC submitted to SideSwap peg-out | Stated by SideSwap |
| No federation or peg-out keys compromised | Stated by Liquid |
| A software bug in Elements caused it | Stated by Blockstream |
| Range-proof cache key omitted asset and script | Independent analysis |
| Block producers ran untagged master-branch code | Unconfirmed report |
| The funds will be returned | Unverified claim |
Bitcoin's base layer was never involved. Liquid trades some of Bitcoin's trust minimisation for speed and confidentiality, and that trade is a legitimate engineering choice. Bitcoin's proof-of-work consensus ran untouched throughout and BTC traded near $80,000 across the event.
But the failure was not exotic. It was a cache key. Every serious chain caches validation results, and every one of those caches carries the same requirement: the key must commit to everything the answer depended on. That requirement is easy to state and easy to violate in a refactor.
The unresolved parts are the important ones. The parties holding the bitcoin describe themselves as whitehats and have conditioned returning most of the funds on the bug being fixed across all nodes. No completed return has been confirmed. Liquid remains paused. A real postmortem still has to establish which code the block producers were running and how it got there — and anyone telling you that today is guessing.
Five true or false. Most people who only read the headlines miss at least two.
A balance check alone proves nothing about hidden amounts. Commitment arithmetic wraps around, so a transaction can create money from nothing and still cancel to a perfect zero. Balancing and range-checking are two halves of one check, and either alone is worthless.
A cache key must commit to everything the answer depended on. Not most of it. Everything. Nothing in the cryptography failed here — the curve, the commitments and the proof system all worked. What failed was the label on the stored answer.
Federated sidechains carry federation risk, and that is a choice, not a flaw. Liquid trades trust minimisation for speed and confidentiality. That trade can be worth making. It is only dangerous when people forget they made it.
Ask what code is actually running. Bugs are inevitable; that is not the alarming part. The alarming part is the unresolved question of how this code reached the machines producing blocks. Ask that about any system holding your money.
Liquid hides transaction amounts, so every output carries a range proof showing the hidden amount is not secretly enormous. Because that check is expensive, nodes cache the result. Independent analysis of the Elements source published on 7 September 2026 indicates the cache key omitted asset and script context, so a result recorded for one validation was reused for a different one where it did not apply. An output that should have been rejected was accepted without being checked, creating roughly 3,996 L-BTC that no bitcoin backed. Blockstream had not confirmed this mechanism at time of writing.
SideSwap stated that a customer submitted 4,000 L-BTC to its peg-out service on 6 September 2026, which released approximately 3,996 BTC, worth about $320 million at the time. The federation wallet had held roughly 4,200 BTC. The peg-out itself was ordinary: under the rules the federation was running, the counterfeit L-BTC was indistinguishable from real L-BTC.
No. Liquid is a federated sidechain built on top of Bitcoin, and the incident involved Liquid's peg-out mechanism and the Elements codebase, not Bitcoin's base layer. Bitcoin's proof-of-work consensus was unaffected and BTC traded near $80,000 through the event.
Range proofs are among the most expensive checks in a confidential transaction, and the same proof is typically verified more than once, first when it enters the mempool and again when it appears in a block. Caching the result avoids repeating the work. Bitcoin Core caches signature and script validation for the same reason. The technique is sound; the reported failure was in what the cache key committed to.
Twice. In August 2010, the value overflow incident created 184.467 billion BTC in block 74638 because two enormous outputs summed past the limits of a 64-bit integer and wrapped around, so the check that outputs cannot exceed inputs passed. In September 2018, CVE-2018-17144 allowed inflation via duplicate inputs after a check had been removed from Bitcoin Core in an earlier performance optimisation.