bugfix: clear BIP39 derivation secrets
What changed, and why it matters
This commit fixes a security bug in the COLDCARD hardware wallet where sensitive BIP39 seed-derivation data was not being securely erased from memory after use. The patch wraps the master-secret generation in a try/finally block and uses blank_object() to wipe the mnemonic words and derived master secret even if an error occurs. Without this fix, an attacker who could read the device's RAM might recover these secrets, though such access is normally difficult on a hardened hardware wallet.
Treat as a security hardening fix and include in the next firmware release. Review other code paths that handle BIP39 mnemonics, passphrases, and master secrets to ensure consistent blank_object() usage. Consider whether 'seed_bits' and the hd object also need explicit wiping after use.
Security signals we found
Sensitive data not cleared after cryptographic use
Use of secure-wipe primitive (blank_object)
try/finally added to ensure cleanup on exception paths
BIP39 seed derivation secrets are the protected asset
Evidence from the diff
In shared/stash.py, the decode() function previously called bip39.master_secret() and hd.from_master() without clearing the intermediate ‘ms’ (master secret bytes) or ‘words’ (mnemonic string). The patch stores the mnemonic words in a local variable, computes the master secret, and then uses blank_object() in a finally block to overwrite both ‘ms’ and ‘words’ regardless of whether an exception is raised. This reduces the window in which plaintext seed material lingers in Python’s heap/stack.
Changed components
shared/stash.pyBIP39 seed decoding / wallet initialization pathInspect captured patch +8 / −3
### shared/stash.py
@@ -120,9 +120,14 @@ def decode(secret, _bip39pw=''):
seed_bits = secret[1:1+ll]
# slow: 2+ seconds
- ms = bip39.master_secret(bip39.b2a_words(seed_bits), _bip39pw)
-
- hd.from_master(ms)
+ words = bip39.b2a_words(seed_bits)
+ ms = None
+ try:
+ ms = bip39.master_secret(words, _bip39pw)
+ hd.from_master(ms)
+ finally:
+ blank_object(ms)
+ blank_object(words)
return 'words', seed_bits, hd
Why this scored 59/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.