require scrolling to reveal passphrase
What changed, and why it matters
This change makes the COLDCARD wallet require the user to scroll down before showing a BIP-39 passphrase on screen. The goal is to reduce the chance that someone nearby (a shoulder-surfer) or a camera can read the secret passphrase when it appears automatically. It is a small user-interface hardening improvement, not a fix for a remote hack.
Treat as a minor defense-in-depth improvement. No urgent action is required for users, but ensure the change is included in the next release and that documentation or release notes mention the new scroll behavior so users are not confused.
Security signals we found
UI hardening to reduce shoulder-surfing exposure of locally entered BIP-39 passphrases
Changelog explicitly calls the change a 'Security Improvement'
Functional test asserts passphrase is hidden until user scrolls
No cryptographic or memory-safety changes
Evidence from the diff
In shared/seed.py, the confirmation message shown after entering a BIP-39 passphrase now inserts a ‘Scroll down to view and verify your passphrase.’ prompt and extra newlines before the line ‘Passphrase: %s’. Because the small screen cannot display the entire message at once, the actual passphrase is pushed off the initially visible area and only appears after the user scrolls. The test in testing/test_bip39pw.py was updated to verify that ‘Passphrase:’ is not visible until the user presses the scroll key. The change is labeled as a ‘Security Improvement’ in the changelog.
Changed components
shared/seed.py:apply_pass_value()testing/test_bip39pw.py:test_bip39_complex()COLDCARD BIP-39 passphrase confirmation UIInspect captured patch +21 / −2
### releases/Next-ChangeLog.md
@@ -94,6 +94,7 @@ This lists the new changes that have not yet been published in a normal release.
## 1.5.1Q - 2026-08-18
+- Security Improvement: Require scrolling to reveal locally entered BIP-39 passphrases.
- Bugfix: Reject malformed multipart BBQrs that could include stale PSRAM bytes
in decoded results. Thanks to [@drk1wi](https://github.com/drk1wi) for reporting this.
- Hardening & Defence in depth:
### shared/seed.py
@@ -1632,7 +1632,8 @@ async def apply_pass_value(new_pp):
msg = ('Above is the master key fingerprint of the new wallet'
' created by adding passphrase to %s.'
- '\n\nPassphrase: %s'
+ '\n\nScroll down to view and verify your passphrase.'
+ '\n\n\nPassphrase: %s'
'\n\nPress %s to abort, %s to use the new wallet, (1) to apply'
' and save to MicroSD for future.') % (msg, new_pp, X, OK)
### testing/test_bip39pw.py
@@ -246,7 +246,8 @@ def test_bip39_add_nums(target, backspaces, pick_menu_item, cap_story, is_q1,
])
def test_bip39_complex(target, pick_menu_item, cap_story, goto_home,
press_select, enter_complex, restore_main_seed,
- verify_ephemeral_secret_ui, go_to_passphrase):
+ verify_ephemeral_secret_ui, go_to_passphrase,
+ cap_screen, is_q1, press_down, press_right):
go_to_passphrase()
from mnemonic import Mnemonic
@@ -255,6 +256,22 @@ def test_bip39_complex(target, pick_menu_item, cap_story, goto_home,
expect = BIP32Node.from_master_secret(seed, netcode="XTN")
enter_complex(target, apply=True)
+ scroll_down = press_down if is_q1 else press_right
+
+ for _ in range(3):
+ screen = cap_screen()
+ assert 'Passphrase:' not in screen
+ if 'Scroll down to' in screen:
+ break
+ scroll_down()
+ time.sleep(.01)
+ else:
+ pytest.fail('passphrase scroll notice not shown')
+
+ scroll_down()
+ time.sleep(.01)
+ assert 'Passphrase:' in cap_screen()
+
press_select()
time.sleep(.1)
verify_ephemeral_secret_ui(xpub=expect.hwif(), is_b39pw=True)Why this scored 43/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.