Merge pull request #10881 from ekzyis/bip32-reject-depth0-nonzero-metadata
What changed, and why it matters
This change tightens validation of BIP32 master keys (the root keys used to derive all wallet addresses). Previously, Electrum would accept an extended public or private key that claimed to be a master key (depth 0) but had a non-zero child number or parent fingerprint. Such keys violate the BIP32 specification and could cause confusion or interoperability problems, but the patch is a defensive validation fix rather than a clear remote-exploitable vulnerability.
Apply the patch. It is a low-risk spec-compliance hardening that prevents malformed master keys from being accepted. Users importing xpubs/xprvs from untrusted sources should ensure they are running a version that includes this validation.
Security signals we found
Input validation hardened for BIP32 extended key parsing
Rejects non-conformant master key metadata per BIP32 spec
Adds regression tests from BIP32 test vectors
No explicit security advisory or CVE referenced in commit
Evidence from the diff
The commit adds a check in BIP32Node.from_xkey() that rejects any xpub/xprv with depth==0 unless both child_number and parent fingerprint are all-zero bytes. This aligns with BIP32 specification requirements for master keys. It also adds unit tests using known BIP32 test vectors. The change is purely input validation and does not, by itself, fix an obvious exploit chain, but it removes a class of malformed keys that downstream code might mishandle.
Changed components
electrum/bip32.pyBIP32Node.from_xkey()Wallet import/seed handling that parses xpub/xprv stringsInspect captured patch +16 / −0
### electrum/bip32.py
@@ -154,6 +154,9 @@ def from_xkey(
xtype = headers_inv[header]
if not allow_custom_headers and xtype != "standard":
raise ValueError(f"only standard xpub/xprv allowed. found custom xtype={xtype}")
+ if depth == 0 and (child_number != bytes(4) or fingerprint != bytes(4)):
+ raise BitcoinException('Invalid extended key: a depth-0 (master) key must have '
+ 'zero child number and zero parent fingerprint')
if is_private:
if xkey[13 + 32] != 0:
raise BitcoinException('Invalid extended private key: '
### tests/test_bitcoin.py
@@ -776,6 +776,19 @@ def test_bip32_from_xkey_private_key_bad_prefix(self):
with self.assertRaises(BitcoinException):
BIP32Node.from_xkey(invalid)
+ def test_bip32_from_xkey_depth0_with_nonzero_child_or_fingerprint(self):
+ # BIP32 requires a depth-0 (master) key to have child number 0 and parent fingerprint 0.
+ for invalid in (
+ # BIP32 test vector 5: zero depth with non-zero parent fingerprint
+ "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv",
+ "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ",
+ # BIP32 test vector: zero depth with non-zero index
+ "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN",
+ "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8",
+ ):
+ with self.assertRaises(BitcoinException):
+ BIP32Node.from_xkey(invalid)
+
def test_is_bip32_derivation(self):
self.assertTrue(is_bip32_derivation("m/0'/1"))
self.assertTrue(is_bip32_derivation("m/0'/0'"))Why this scored 44/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.