Back to Blog

~$320M Lost: Liquid Network, Symbiosis Exploits | BlockSec

Code Auditing
September 17, 2026
13 min read
Key Insights
  • This report covers 2 security incidents totaling approximately $320M in losses across the Liquid Network, a Bitcoin sidechain, and Symbiosis, a Bitcoin bridge deployed on BNB Smart Chain, Ethereum and Rootstock. The Liquid Network exploit drove over 99% of the total, with Symbiosis accounting for an estimated $770K.

  • In both cases the check that should have stopped the forgery ran and reported success while attesting to the wrong thing. A Liquid node returned true for a rangeproof it never examined, because a verdict for a different proof had been filed under the same cache key. Symbiosis's signers produced a valid signature over a mint amount that their own Bitcoin-side decoder had computed from fields the depositor controlled.

  • What a forged balance is worth depends on the exit, not on its face value. Nearly all of Liquid's 4,000 unbacked L-BTC left through the two-way peg as real bitcoin, and ~$320M moved; the syBTC Symbiosis minted came to more than two thousand times the supply of bitcoin, but the pools it had to be sold through held 11.26 syBTC, and the loss to liquidity providers and users came to an estimated 9.97 BTC.

During the past week (2026/09/07 - 2026/09/13), we observed 2 security incidents with a total estimated loss of approximately $320M.

Date Incident Type Estimated Loss
2026/09/06 * Liquid Network Flawed Cache Key Construction ~$320M
2026/09/11 Symbiosis Flawed Off-Chain Deposit Validation ~$770K

*The Liquid Network incident occurred on September 6 and was not covered in last week's report. It is included here for completeness.

Best Security Auditor for Web3

Validate design, code, and business logic before launch

Weekly Highlight: Liquid Network

The Liquid Network incident was selected for its subtle cache-key collision mechanism and the substantial losses it caused. By crafting a transaction whose validation data re-divided the bytes of an earlier one, the attacker had a cached validation result returned for a proof that was never checked.

On 2026/09/06, the Liquid Network, a Bitcoin sidechain, was exploited for approximately $320M [1]. A collision in the rangeproof validation cache of Elements, the node software Liquid runs, allowed a valid verdict recorded for one output to be returned for a second, entirely different output, whose proof was therefore accepted without ever being examined. The attacker used this to create 4,000 L-BTC that no bitcoin backed, then withdrew them through the network's ordinary peg-out. The following day 3,400 BTC was returned to the federation, leaving about 598.5 BTC with the attacker [2].

Background

The Liquid Network is a Bitcoin sidechain built on Elements, an open-source blockchain platform derived from the Bitcoin codebase. It exists to move bitcoin faster, more cheaply and more privately than the main chain allows. Bitcoin crosses between the two networks through a two-way peg: in a peg-in, a user locks BTC with the network's federation, a fixed group of vetted organizations that jointly custody the peg funds, and receives an equal amount of L-BTC; in a peg-out, the user destroys L-BTC and the federation releases the corresponding BTC. Liquid blocks are not mined. A rotating set of the federation's functionary nodes proposes them, and a threshold of federation signatures finalizes them.

Like Bitcoin, Liquid tracks funds as unspent transaction outputs rather than as account balances. A transaction names existing unspent outputs, unlocks them, and creates new ones, and the value it creates must equal the value it consumes. Every output carries a locking script, its scriptPubKey. An output whose script begins with OP_RETURN can never be spent; it exists to carry data, and a peg-out is expressed as exactly that kind of output.

Liquid also hides amounts by default. Rather than writing a figure into an output, it writes a Pedersen commitment to that figure. Commitments are additive, so a node can confirm that a transaction's inputs and outputs balance without learning any of the values involved. That property cuts both ways: a commitment can just as well hide a value that behaves as negative, which would let a transaction's outputs exceed its inputs and still balance. Every output whose amount is hidden therefore carries a rangeproof, a proof that the committed amount lies within [0, 2^64). Verifying a rangeproof is expensive, and the same output is verified more than once — when the transaction enters the mempool, and again when it arrives in a block — so Elements keeps a cache of the proofs it has already accepted, keyed by the proof and the data it was checked against.

Vulnerability Analysis

The defect is in how Elements, the node software every Liquid participant runs, caches already-verified rangeproofs.

CachingRangeProofChecker::VerifyRangeProof() derives a cache entry for the output in front of it and, on a hit, returns success immediately without touching the proof:

The entry comes from ComputeEntryRangeProof(), which writes four fields one after another into a single SHA-256 stream and finalizes the digest:

The four fields are the rangeproof itself, the Pedersen commitment to the amount, the asset generator that identifies which asset the output holds, and the scriptPubKey, included so that an accepted proof binds to one specific locking script.

None of the four fields carries a length prefix or a separator. The rangeproof and the scriptPubKey vary in length; the Pedersen commitment and the asset generator are always 33-byte points. The digest therefore records only the concatenated bytes, with nothing to mark where one field ended and the next began. Two different sets of four fields that happen to concatenate to the same byte stream produce the same entry, and whichever is validated first leaves behind a verdict the other one collects. The hasher is seeded with a per-node random salt, but the salt is prefixed to both streams alike, so it changes the digest without distinguishing the two inputs. The defect was remediated in commit 94000967 [3].

Attack Analysis

The following analysis is based on the transactions 271147...187ec5 and f24a4b...0a183f, both accepted by nodes running the vulnerable code.

  • Step 1: The attacker published a transaction whose first output is an OP_RETURN carrying 67 bytes of data.

Its scriptPubKey reads 6a 43 — the OP_RETURN opcode followed by a push of 67 bytes — then two 33-byte values and a trailing 6a. Those 67 pushed bytes are not data this transaction needs. They are the value commitment and the asset generator of an output that did not exist yet. Validating this output stored a valid verdict under the entry for its own four fields.

  • Step 2: The attacker then submitted the inflation transaction. Its OP_RETURN output has a scriptPubKey consisting of the single byte 6a, and its value commitment is exactly the 33-byte value embedded in the earlier transaction's push. Its rangeproof field was built from the earlier transaction's rangeproof, commitment and asset generator, followed by the two bytes 6a 43.

The four fields of this output therefore concatenate to the same byte stream as the first transaction's, re-divided along different boundaries:

Primer:     P0 │ C0 │ X │ S0,  where S0 = 6a 43 <33-byte C1> <33-byte X> 6a
Inflation:  P1 │ C1 │ X │ S1,  where P1 = P0 ‖ C0 ‖ X ‖ 6a 43  and  S1 = 6a

Both concatenate to:  P0 ‖ C0 ‖ X ‖ 6a 43 ‖ C1 ‖ X ‖ 6a

The cache returned the earlier verdict, and P1 was never verified — it is not a rangeproof at all. C1 commits to a small negative amount. The transaction's other output, a normal pay-to-witness-public-key-hash output to the attacker's address ex1q7kg...qa2w, carried a large positive commitment with a genuine rangeproof, and the two offset each other, so the transaction balanced. It left 4,000 unspent L-BTC that no bitcoin backed.

  • Step 3: The attacker pegged out. Two transactions burned 3,996.01834922 and 2.65138358 L-BTC through ordinary OP_RETURN peg-out outputs, 3,998.66973280 L-BTC in total. The functionary nodes that authorize peg-outs validated them with the same vulnerable code and released the bitcoin: 3,995.99999857 BTC and 2.49749857 BTC reached the attacker on Bitcoin, 3,998.49749714 BTC in all.

The network paused and split into two chains while the incident was resolved [4], and resumed with the invalid peg-out rejected [2]: a block explorer today shows the primer transaction confirmed but not the inflation transaction, even though the bitcoin it released had already left the federation's wallet. At 16:09:25 UTC the next day, the attacker returned 3,400.00000000 BTC to the federation's peg wallet, keeping the remaining ~598.5 BTC outstanding [2], as the two sides negotiated through messages embedded in Bitcoin transactions [4].

Conclusion

The attacker broke no cryptography and compromised no key. The defect was in how the rangeproof cache identified what it had already checked. Its key concatenated four fields — two of them variable in length — into one hash stream with nothing marking where each field ended, so a second set of fields could re-divide the same bytes and land on the same entry. A stored valid verdict was then returned for a proof no node had ever verified, and once a rangeproof stops constraining the amount behind it, a confidential ledger loses the only thing keeping its hidden values non-negative. One crafted output became 4,000 L-BTC, and the two-way peg turned them into bitcoin on the main chain.

Any identifier derived from more than one variable-length input has to commit to the boundaries between them, whether by prefixing each field with its length or by hashing the fields into separate fixed-size slots. Without that the derivation is not injective, and two distinct inputs can be mistaken for one. The requirement is sharpest wherever a cache stands in for a check, because there a hit is a decision not to run it.


More Incidents This Week

Symbiosis

On 2026/09/11, the Bitcoin route of the Symbiosis cross-chain bridge was exploited across its BNB Smart Chain, Ethereum and Rootstock deployments, costing liquidity providers and users an estimated 9.97 BTC (~$770K, at the ~$77K September-11 price) [5]. Off-chain code that decides how much synthetic bitcoin to mint from a Bitcoin deposit took the depositor's identity from a part of the transaction the depositor controls, letting the attacker pass as the administrator and push the minimum fee below zero; it then subtracted that fee from the deposit without checking its sign, so the subtraction added.

Background

Symbiosis is a cross-chain liquidity protocol that moves value between chains by locking and minting rather than by transferring the asset itself: on chains with smart contracts, a user's tokens are locked by the Portal contract on the source chain, and the Synthesis contract mints an equal amount of a synthetic token, an sToken, on the host chain; burning the sToken releases the original [6]. Bitcoin arrives through this route as syBTC, a token with 8 decimals matching bitcoin's own smallest unit, issued on BNB Smart Chain, Ethereum and Rootstock and paired in pools against BTCB, cbBTC, WBTC and RBTC [5].

Bitcoin has none of that: no smart contracts, so no Portal contract to lock deposits. In its place is the portal — a designated Bitcoin address that plays the same role. A deposit is an ordinary Bitcoin transaction paying it, with the instructions for the destination chain attached to it as data. Off-chain code belonging to the bridge reads that data to learn who is depositing, how much, and where the synthetic token should go, and enforces the portal's fee — subtracted from the deposited amount before the amount to mint is fixed — whose minimum is a parameter its administrator sets.

Nothing about the Bitcoin side is visible to the destination chain, so a Relayers Network carries the resulting request across. The request arrives at BridgeV2, the bridge's on-chain entry point, as an encoded call that it forwards to Synthesis. Authorization rests on an MPC key: the protocol's signers hold shares of a single private key and jointly produce one signature over the request. The entry point for relayed requests carries a single modifier and does nothing else before dispatching the call:

That modifier hashes the request and requires the accompanying signature to be valid for the MPC address:

What the contract establishes is that the MPC key signed the request. The amount the request carries is computed on the Bitcoin side.

Vulnerability Analysis

The defect is not in the destination-chain contracts. It is in the off-chain service that reads Bitcoin deposits and turns them into cross-chain requests. Its source is not publicly available, so the account below follows the team's post-mortem [5] together with a 2024 third-party audit report that contains a code snippet which appears related [7].

Two flaws in the deposit path had to line up, and the post-mortem states that neither was sufficient on its own.

The first is in how the depositor is identified. The instructions attached to a deposit are decoded to recover who is making it, and the decoder took that identity from a part of the transaction data that whoever spends the input controls. A depositor could therefore name themselves as any party the protocol recognizes, including the portal's administrator, the role that sets the minimum fee the portal will accept.

The second is in how that fee is applied. The 2024 audit reported the line in decodeWrap() that computes the amount to mint by subtracting the fee from the value of the deposit output:

Value: types.Satoshi(tx.TxOut[idx].Value) - info.PortalFee,

Its finding was that types.Satoshi is a signed integer type while the info structure carrying PortalFee is untrusted and user-controlled, so the result can be driven negative and, serialized for the destination chain as an unsigned value, becomes large enough to mint an arbitrary quantity of synthetic bitcoin. The audit recorded the issue as fixed at the time [7]. The 2026 post-mortem describes the same kind of failure: the fee was subtracted from the deposit without a check on its sign [5], so a fee below zero enlarged the deposit rather than reducing it. Nothing in the deposit path appears to bound the amount to mint by the bitcoin actually received.

Attack Analysis

Twelve forged mints went through across BNB Smart Chain, Ethereum and Rootstock in roughly four minutes [5]. The following analysis is based on one of them, the transaction 0x9a2bc0...21b9b959 on BNB Smart Chain.

  • Step 1: Passing as the portal's administrator, the attacker moved the minimum fee the portal accepts below zero, so that a deposit declaring a negative fee would be processed instead of rejected [5].

  • Step 2: The attacker deposited 330 satoshi, which appears as 0x000000000000014a. The request that reached BNB Smart Chain carried 0x400000000000014a — the same value with the bit for 2^62 set, 4,611,686,018,427,388,234 base units. The difference between the two is exactly 2^62, so the fee subtracted from this deposit was -4,611,686,018,427,387,904 satoshi:

    330 - (-4,611,686,018,427,387,904) = 4,611,686,018,427,388,234

    The request was signed and relayed in that form.

  • Step 3: receiveRequestV2Signed() verified the MPC signature over the request and passed it on, reaching metaMintSyntheticTokenBTC(). That function resolved the synthetic representation of the real token for the source chain ID, syBTC, and called synthesize() for the full signed amount. All of it was transferred to the attacker's address 0x025122...5d3Ba2: 46,116,860,184.27388234 syBTC.

  • Step 4: The attacker sold the synthetic token into the pools holding it. A single swap through a Uniswap v4 syBTC/WBTC pool settled 18,446,744,072,845,450,682 base units of syBTC, about four times what the transaction above minted, and took out 4.38897292 WBTC.

Routed onward, the proceeds of that swap came to roughly 137 ether.

The team paused the Bitcoin route, and about 15.2 BTC of portal funds were moved to reserve addresses within hours [5]. A bounty of 20% of anything returned was offered, open until September 13 [8]. The protocol's other routes were unaffected.

Conclusion

No key was stolen and no contract was tricked into running code it was not written to run. The signature the destination chain checked was genuine; what it authorized was a number that off-chain code had already produced incorrectly in two separate ways: once when it read the depositor's identity from a field the depositor controls, letting the attacker pose as the portal's administrator and push its minimum fee below zero, and again when it subtracted that fee from the deposit without checking its sign, so a negative fee enlarged the deposit instead of reducing it.

An identity read out of untrusted input is not an identity: a privileged role can only be established by something the depositor cannot choose, such as the address that actually authorized the spent input, checked against a list the protocol maintains — not a field the depositor is free to fill in. A value that is subtracted needs bounds on both sides: a fee should be required to fall between zero and the deposit, and the amount to mint should never be permitted to exceed what the source chain actually received. Either bound would have stopped this on its own.

Get Started with Phalcon Security

Detect every threat, alert what matters, and block attacks.

Try now for free

References

[1] https://x.com/Liquid_BTC/status/2096696272447218108

[2] https://x.com/Liquid_BTC/status/2097404704028545175

[3] https://github.com/ElementsProject/elements/commit/94000967f6dc05b1afd435e79b1bbc597e29f816

[4] https://www.coindesk.com/markets/2026/09/08/white-hat-hackers-return-most-of-usd320m-bitcoin-taken-from-liquid-network

[5] https://x.com/symbiosis_fi/status/2099566361940795831

[6] https://docs.symbiosis.finance/crosschain-liquidity-engine/synthesizing-process

[7] https://github.com/symbiosis-finance/audits/blob/master/Symbiosis%20Relayers%20Network/Symbiosis%20Relayers%20Network%202024%20-%20Decurity.pdf

[8] https://x.com/symbiosis_fi/status/2098442463358718264

About BlockSec

BlockSec is a full-stack blockchain security and crypto compliance provider. We build products and services that help customers to perform code audit (including smart contracts, blockchain and wallets), intercept attacks in real time, analyze incidents, trace illicit funds, and meet AML/CFT obligations, across the full lifecycle of protocols and platforms.

BlockSec has published multiple blockchain security papers in prestigious conferences, reported several zero-day attacks of DeFi applications, blocked multiple hacks to rescue more than 20 million dollars, and secured billions of cryptocurrencies.

Sign up for the latest updates
~$9.4M Lost: Injective, Aquifer Exploits | BlockSec Weekly
Security Insights

~$9.4M Lost: Injective, Aquifer Exploits | BlockSec Weekly

During the past week (2026/08/31 - 2026/09/06), four security incidents caused approximately $9.4M in losses across Injective, Solana, Ethereum, and Flow EVM. The largest was the Injective exploit, where an insurance fund identifier collided with a binary options market identifier and the settlement path never compared their denominations, draining about $4.8M; Aquifer on Solana lost about $2.47M because its swap path invoked an unvalidated caller-supplied Token Program, and Notional Finance V1 on Ethereum lost about $1.73M to an unchecked `uint128` cast that valued a debt at zero. Ankr FLOW on Flow EVM closed out the week with about $410K drained through a staking entry point that skipped its pause guard and minted against a stale ratio.

From Incidents to Regulation: Why Crypto Institutions Need Blockchain Penetration Testing
Security Services

From Incidents to Regulation: Why Crypto Institutions Need Blockchain Penetration Testing

Exchanges, payment firms, custodians, and wallet providers now lose the most money beyond the smart contract—in signing, custody, keys, people, and supply chains. Code-level audit and transaction-level monitoring each leave a gap, and traditional penetration tests may miss crypto's signing and fund semantics. This article opens our blockchain penetration testing series with the two legs of the case for institutions in scope: where the risk actually comes from, and how NYDFS, DORA, VARA, SFC, and MAS treat adversarial testing across five jurisdictions.

What Is Blockchain Penetration Testing? Definitions and Boundaries
Security Services

What Is Blockchain Penetration Testing? Definitions and Boundaries

No widely accepted definition of blockchain penetration testing exists, and many proposed ones tangle it with audit, scanning, and bug bounty. This article sets out a working definition—an adversarial, hands-on assessment of a running system, under agreed scope and rules of engagement, that validates exploitable paths and control chains—and what web3 adds: a money-handling threat model whose defining composition gap is the off-chain-to-on-chain handoff. It then maps the five testable capabilities of that chain and routes nearby objectives to code audit, wallet security audit, web3 security testing, scanning, and bug bounty.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit