Skip to content
← Blog · · df00tech

CVE-2026-107846: bitcoinjs-lib Merkle Root Validation Fails to Detect Duplicated-Transaction Block Mutation (CVE-2012-2459 Reborn)

breaking ghsa npm CVE-2026-107846

What happened

A GitHub Security Advisory (GHSA-8vv3-6qpc-gpw6, tracked as CVE-2026-107846) reports that bitcoinjs-lib's fastMerkleRoot function pads an odd number of transaction hashes at a merkle tree level by hashing the last node with itself, but never reports when it does so. The library's block-integrity check, checkTxRoots (via Block.calculateMerkleRoot and __checkMerkleRoot), only compares the computed root to the header field. It never scans for adjacent duplicate hashes or repeated transaction IDs.

This is a reintroduction of CVE-2012-2459, a historical Bitcoin Core merkle-tree mutation bug. Bitcoin Core itself defends against it. ComputeMerkleRoot sets a mutated flag when it finds two adjacent equal hashes at any level, and CheckBlock rejects such blocks with bad-txns-duplicate. bitcoinjs-lib has no equivalent check.

The advisory includes a working proof of concept against a real mainnet block. Duplicating the last transaction (going from 9 to 10, and separately to 12 transactions) produces a different, larger serialized block with the same merkle root and the same block id, and checkTxRoots() accepts all variants. Affected versions span 2.3.0 through 5.2.0, 6.0.0 through 6.1.7 (including 6.1.0-rc.0), and 7.0.0-rc.0 through 7.0.1.

Why it matters for defenders

Any application using bitcoinjs-lib to validate a block's transaction list, such as block explorers, exchange or custody indexers, or SPV-style clients, can be fed a relayed, mutated copy of a legitimate block containing a duplicated transaction. Because the block hash and id never change, header-level trust checks will not catch it. A consumer that credits a deposit per occurrence of a transaction in the block could credit the same deposit twice. Separately, a consumer that reacts to a detected mutation by blacklisting the block hash would also reject the honest version of that block, creating a denial-of-service or chain-split condition. Severity is scoped to how much a given deployment relies on checkTxRoots-style block validation versus transaction-level handling, which the advisory notes is a smaller slice of this library's typical usage.

What defenders should watch for or do now

  • Inventory any service using bitcoinjs-lib (directly or via a dependency) that parses raw blocks and relies on Block.checkTxRoots() or calculateMerkleRoot() for integrity decisions, not just transaction signing or wallet code.
  • Upgrade to the patched releases named in the advisory: 5.2.1, 6.1.8, or 7.0.2 (or a later release on the corresponding line). Versions below v5 have no in-line patch and require moving to a fixed line.
  • As a hunting and monitoring angle, flag any ingested block whose transaction list contains a repeated txid, or where re-serialization produces a byte length inconsistent with a previously seen block of the same id. Both are symptoms the fix explicitly targets.
  • If you cannot patch immediately, consider adding an application-level check that rejects blocks containing duplicate transaction IDs before trusting checkTxRoots() output, mirroring Bitcoin Core's mutated and bad-txns-duplicate logic.

Developing intel

This is a same-day advisory disclosure with a public proof of concept. Downstream exposure (which products and services embed the vulnerable bitcoinjs-lib versions) is still being assessed. We will track further detail as it emerges. Full technical writeup and PoC: GHSA-8vv3-6qpc-gpw6.

Get new detections in your inbox

New ATT&CK coverage plus CISA KEV / CVE detection rules, roughly weekly. No spam, unsubscribe anytime.