What changed, and why it matters
This commit makes several small changes to the COLDCARD firmware. It removes a debug print statement that exposed internal warnings, blocks certain key-teleport QR codes when the device is in a restricted 'hobbled' mode, and removes a 'has_secrets' safety check from wallet export menu items in hobbled mode. The changes appear to be hardening and UI consistency fixes rather than a clear security patch, but one change weakens an access-control predicate while others strengthen restrictions.
Review whether removing predicate=has_secrets from the hobbled-mode 'Export Wallet' menu items is intentional and safe; verify that hobbled_mode itself provides equivalent or stronger protection. Otherwise, treat as a routine firmware update with minor hardening changes.
Security signals we found
Access-control predicate removed from wallet export menus in hobbled mode
Debug print of sensitive PSBT warning data removed
Additional hobbled_mode enforcement added to key-teleport QR decoding and incoming teleport handling
Silent return path added for blocked teleport operations
Evidence from the diff
The diff touches five files. In ccc.py, a debug print of PSBT warnings is removed. In decoders.py, QR decoding of key-teleport types ‘R’, ‘S’ (and implicitly ‘E’) is now blocked in hobbled_mode except for type ‘E’. In flow.py, the ‘Export Wallet’ menu items in HobbledFileMgmtMenu and HobbledAdvancedMenu lose the predicate=has_secrets guard. In notes.py, hobbled_mode is checked before building the notes menu. In teleport.py, an incoming key-teleport type other than ‘E’ silently returns in hobbled_mode, with a comment noting this is the second check after decoders.py. The commit message is only ‘improvements’ and provides no security framing.
Changed components
shared/ccc.pyshared/decoders.pyshared/flow.pyshared/notes.pyshared/teleport.pyInspect captured patch +10 / −4
diff --git a/shared/ccc.py b/shared/ccc.py
index 397b7ce..90eb801 100644
--- a/shared/ccc.py
+++ b/shared/ccc.py
@@ -81,7 +81,6 @@ class SpendingPolicy(dict):
# not safe to sign any txn w/ warnings: might be complaining about
# massive miner fees, or weird OP_RETURN stuff
if psbt.warnings:
- print("WARN: %r" % psbt.warnings)
raise SpendPolicyViolation("has warnings")
# Magnitude: size limits for output side (non change)
diff --git a/shared/decoders.py b/shared/decoders.py
index a259dd8..2e1505c 100644
--- a/shared/decoders.py
+++ b/shared/decoders.py
@@ -139,6 +139,11 @@ def decode_qr_result(got, expect_secret=False, expect_text=False, expect_bbqr=Fa
elif ty in 'RSE':
# key-teleport related
+
+ from pincodes import pa
+ if pa.hobbled_mode and ty != 'E':
+ raise QRDecodeExplained("KT Blocked")
+
if ty == 'R' and len(got) != 33:
raise QRDecodeExplained("Truncated KT RX")
diff --git a/shared/flow.py b/shared/flow.py
index 372a920..3ddf6c4 100644
--- a/shared/flow.py
+++ b/shared/flow.py
@@ -491,7 +491,7 @@ HobbledFileMgmtMenu = [
MenuItem('Sign Text File', f=sign_message_on_sd),
MenuItem('Batch Sign PSBT', f=batch_sign),
MenuItem('List Files', f=list_files),
- MenuItem('Export Wallet', predicate=has_secrets, menu=WalletExportMenu), #dup elsewhere
+ MenuItem('Export Wallet', menu=WalletExportMenu), # dup under Adv/Tools
MenuItem('Verify Sig File', f=verify_sig_file),
MenuItem('NFC File Share', predicate=nfc_enabled, f=nfc_share_file, shortcut=KEY_NFC),
MenuItem('BBQr File Share', predicate=version.has_qr, f=qr_share_file, arg=True),
@@ -516,7 +516,7 @@ HobbledNFCToolsMenu = [
HobbledAdvancedMenu = [
# xxxxxxxxxxxxxxxx
MenuItem("File Management", menu=HobbledFileMgmtMenu),
- MenuItem('Export Wallet', predicate=has_secrets, menu=WalletExportMenu, shortcut='x'), # also inside FileMgmt
+ MenuItem('Export Wallet', menu=WalletExportMenu, shortcut='x'), # also inside FileMgmt
MenuItem('Teleport Multisig PSBT', predicate=qr_and_ms, f=kt_send_file_psbt),
MenuItem("View Identity", f=view_ident),
MenuItem('Paper Wallets', f=make_paper_wallet),
diff --git a/shared/notes.py b/shared/notes.py
index ddb2dd4..6a5d2a6 100644
--- a/shared/notes.py
+++ b/shared/notes.py
@@ -21,6 +21,8 @@ from utils import problem_file_line, url_unquote, wipe_if_deltamode
ONE_LINE = CHARS_W-2
async def make_notes_menu(*a):
+ from pincodes import pa
+
if pa.hobbled_mode:
# Read only version of menu system
# - used when spending policy in effect
diff --git a/shared/teleport.py b/shared/teleport.py
index f4e2ead..37f8db3 100644
--- a/shared/teleport.py
+++ b/shared/teleport.py
@@ -484,7 +484,7 @@ async def kt_incoming(type_code, payload):
from pincodes import pa
if pa.hobbled_mode and type_code != 'E':
# only PSBT rx is supported in hobbled mode
- # TODO: fail silently? good enough?
+ # fail silently, this is second check, see decoders.py
return
if type_code == 'R':
Why this scored 49/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.