News

Combining two PSBTs could make a file nothing can read

Bitcoin Core merged a fix on 19 August 2026 for combinepsbt, which could return a partially signed transaction that its own deserialiser rejects. Every release since v23.0 can still produce one.

4 min readWallet Standards
Combining two PSBTs could make a file nothing can read

What happened

On 19 August 2026 Bitcoin Core merged pull request 35665, which stops combinepsbt from producing a file that nothing, including the node that produced it, can read back. The pull request gives a reproduction on master: combining two partially signed transactions that differ only in one field returns a result that decodepsbt rejects with error code: -22 and the message TX decode failed Duplicate Key, global key "01043587cf00...9c85c2" already provided. It also gives the age of the bug: "This affects all releases since the merge loop was added in #17034 (v23.0)."

What it changes

A PSBT is the file two wallets pass back and forth to build a spend that needs more than one signature. It is a list of key-value records, and its central rule is a rule about keys: "Keys within each scope should never be duplicated; all keys in the format are unique. PSBTs containing duplicate keys are invalid."

One kind of record carries an extended public key, so a signer can work out which keys in the transaction belong to which wallet. In that record the key is the xpub itself, and the value is its origin: the master key fingerprint and the derivation path. Core held the same information in memory the other way round, as the pull request describes: "Global xpubs are stored in a map of key origin to set of xpubs, while the serialization writes one record per xpub, keyed by the xpub."

Merging then followed the shape of the memory structure rather than the shape of the file. Merge unions the map origin by origin, so two PSBTs that name the same xpub under two different origins produce a result that writes the same PSBT_GLOBAL_XPUB key twice. The uniqueness rule lives in the key; the structure being merged was not keyed by it. In the reproduction the two files share the unsigned transaction and the xpub and "differ only in the master fingerprint of the global xpub record (00000000 vs 11111111)", which is enough.

The fix deduplicates by xpub when merging and keeps the origin already present, which the standard permits: BIP 174 lets the Combiner "pick arbitrarily when conflicts occur", and Core already resolved conflicting unknown and proprietary records the same way. The logic now lives in one helper, MergeGlobalXPubs, shared by combinepsbt and joinpsbts.

What it does not change

Nobody lost coins to this and nobody could. The failure is loud and it happens at parse time, not at signing time: the merged file is rejected before any signature is checked, so what the bug destroys is a coordination round, not money. That is worth stating plainly because the opposite bug, a merge that silently produced a valid-looking file with wrong key origins, is the one that would matter.

The conflict is not resolved either, it is dropped. Keeping the first origin means the other signer's claim about the fingerprint and derivation path disappears without comment. If two devices in a multisig disagree about where an xpub came from, the merged file will now parse, and the disagreement it recorded will not be in it. Verifying that an xpub really is yours is still done on the signing device, which is where it was always done.

Nothing installed anywhere is fixed by this. The change is on master, and by the pull request's own account every release since v23.0 produces the bad file, so until a release carries the fix the practical answer is not to merge PSBTs whose global xpub origins disagree. The joinpsbts half is pre-emptive rather than corrective: the author notes that its xpub loop "currently has no observable effect, since the collected xpubs never reach the returned PSBT", and that a separate pending change would make the same duplicate reachable there if the shared helper were not already in place.

Context

The interesting part is not the bug, it is where it lived. Nothing was wrong with the format, the specification, the cryptography or the signatures. Two representations of one fact disagreed about which field was the identity, and the invalid file came out of the gap between them.

Extended public keys keep turning up at this seam because a multisig has to move them around to work at all. Core added a way to hand out an xpub at a chosen path this month, and BIP-89 reached Deployed on the case for not handing one over at all. What a co-signer knows about the other keys, how it learns it, and what it does when two sources disagree is the same question in each of them.

Newsletter

Bitcoin, without the noise

What happened in Bitcoin, what it actually changes, and the sources so you can check us. One issue at a time, straight to your inbox.

  • One email per issue, never a drip campaign
  • No tracking pixels and no shared addresses
  • Unsubscribe from any issue in one click

Get the next issue

One email per issue, no tracking pixels, and unsubscribe from any of them. We do not share your address. Privacy policy