bugfix: guard permanent key imports with temporary wallets
What changed, and why it matters
This commit fixes a bug in the COLDCARD hardware wallet where importing a permanent private key could incorrectly be allowed while a temporary wallet was still active. The old check only verified that the main secure-element secret was blank, but that condition can be true even when a temporary wallet is loaded. The new check ensures no secret of any kind is active before a permanent key import proceeds. If the bug were triggered, a permanent import might overwrite or coexist unexpectedly with an active temporary wallet, potentially confusing the user about which wallet is in control or causing loss of funds if the wrong wallet is used.
Treat as a security-relevant bugfix. Review whether the assertion is the only guard or whether UI/flow controls already prevent reaching these code paths with a temporary wallet active. If the assertion can be reached, ensure the error is surfaced clearly to the user and consider adding an explicit test case for permanent import while a temporary wallet is loaded. No CVE or advisory is supplied, so monitor vendor communications for further guidance.
Security signals we found
Precondition strengthening for destructive/critical operation
Potential state-confusion between temporary and permanent wallets
Assertion-based guard (defense in depth, not primary access control)
Bugfix in seed/key import code paths
Evidence from the diff
In shared/actions.py’s import_xprv() and shared/tapsigner.py’s import_tapsigner_backup_file(), the guard for non-ephemeral (permanent) key imports was changed from assert pa.is_secret_blank() to assert not pa.has_secrets(). The old predicate only confirmed the main secure element (SE) seed was blank, but a blank SE can still have a temporary wallet active. Permanent imports require no active secret at all, so the assertion was too weak. The patch tightens the precondition to block permanent imports whenever any secret (including a temporary wallet) is present.
Changed components
shared/actions.py: import_xprv()shared/tapsigner.py: import_tapsigner_backup_file()COLDCARD wallet import subsystempincodes module (pa.has_secrets / pa.is_secret_blank)Inspect captured patch +6 / −2
### shared/actions.py
@@ -1409,7 +1409,9 @@ async def import_xprv(_1, _2, item):
ephemeral = item.arg
if not ephemeral:
- assert pa.is_secret_blank() # "must not have secret"
+ # A blank SE can still have a temporary wallet active.
+ # Permanent imports require no active secret.
+ assert not pa.has_secrets()
def contains_xprv(fname):
# just check if likely to be valid; not full check
### shared/tapsigner.py
@@ -31,7 +31,9 @@ async def import_tapsigner_backup_file(_1, _2, item):
ephemeral = item.arg
if not ephemeral:
from pincodes import pa
- assert pa.is_secret_blank() # "must not have secret"
+ # A blank SE can still have a temporary wallet active.
+ # Permanent imports require no active secret.
+ assert not pa.has_secrets()
origin = "from "
label = "TAPSIGNER encrypted backup file"Why this scored 58/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.