Removing the special handling and the warning for the suspicious derivation paths
What changed, and why it matters
This commit removes a warning screen that previously appeared when a Bitcoin public key was requested for an unusual or non-standard derivation path. Without the warning, users may be less likely to notice if malicious software asks their Ledger device to reveal keys for a suspicious path. The change itself is a deliberate feature removal, not a hidden bug, but it weakens a user-facing safety check.
Treat this as a security-relevant UX change. Review whether the removed warning is still required by Ledger's security model or compliance obligations. If retained, consider reintroducing an equivalent warning or requiring explicit user acknowledgment for non-standard derivation paths when exporting extended public keys. If the removal is intentional and accepted, document the rationale and ensure downstream documentation and security audits are updated.
Security signals we found
Removal of a user-facing security warning for unusual BIP32 derivation paths
Deletion of `ui_display_pubkey_suspicious_flow()` and related generic-content UI code
Change in `handler_get_extended_pubkey()` stops computing or passing `!is_safe` to the UI
Reduced visibility for non-standard key derivation requests during public-key export
Evidence from the diff
The patch deletes the is_path_suspicious parameter and the ui_display_pubkey_suspicious_flow() implementation across get_extended_pubkey.c, display.c, display.h, and display_nbgl.c. Previously, handler_get_extended_pubkey() computed a boolean is_safe and passed !is_safe to the UI layer; now it always calls the standard ui_display_pubkey_flow(). The removed suspicious-path flow showed a ‘WARNING / The derivation path is unusual’ centered-info page before the normal path/public-key tag-value review. The commit message explicitly states this is intentional removal of special handling and the warning.
Changed components
src/handler/get_extended_pubkey.csrc/ui/display.csrc/ui/display.hsrc/ui/display_nbgl.cInspect captured patch +2 / −96
diff --git a/src/handler/get_extended_pubkey.c b/src/handler/get_extended_pubkey.c
index 0e7b158..e9c6318 100644
--- a/src/handler/get_extended_pubkey.c
+++ b/src/handler/get_extended_pubkey.c
@@ -167,7 +167,7 @@ void handler_get_extended_pubkey(dispatcher_context_t *dc, uint8_t protocol_vers
bip32_path_format(bip32_path, bip32_path_len, path_str, sizeof(path_str));
}
- if (display && !ui_display_pubkey(dc, path_str, !is_safe, pubkey_str)) {
+ if (display && !ui_display_pubkey(dc, path_str, pubkey_str)) {
SEND_SW(dc, SW_DENY);
return;
}
diff --git a/src/ui/display.c b/src/ui/display.c
index 9e26f68..4b206a9 100644
--- a/src/ui/display.c
+++ b/src/ui/display.c
@@ -97,7 +97,6 @@ static bool io_ui_process(dispatcher_context_t *context) {
bool ui_display_pubkey(dispatcher_context_t *context,
const char *bip32_path_str,
- bool is_path_suspicious,
const char *pubkey) {
#ifdef HAVE_AUTOAPPROVE_FOR_PERF_TESTS
return true;
@@ -108,11 +107,7 @@ bool ui_display_pubkey(dispatcher_context_t *context,
strncpy(state->bip32_path_str, bip32_path_str, sizeof(state->bip32_path_str));
strncpy(state->pubkey, pubkey, sizeof(state->pubkey));
- if (!is_path_suspicious) {
- ui_display_pubkey_flow();
- } else {
- ui_display_pubkey_suspicious_flow();
- }
+ ui_display_pubkey_flow();
return io_ui_process(context);
}
diff --git a/src/ui/display.h b/src/ui/display.h
index f33a1f0..0cbdc9b 100644
--- a/src/ui/display.h
+++ b/src/ui/display.h
@@ -137,7 +137,6 @@ typedef void (*action_validate_cb)(dispatcher_context_t *dispatcher_context, boo
*/
bool ui_display_pubkey(dispatcher_context_t *context,
const char *bip32_path_str,
- bool is_path_suspicious,
const char *pubkey);
bool ui_display_message_and_confirm(dispatcher_context_t *context,
@@ -145,11 +144,6 @@ bool ui_display_message_and_confirm(dispatcher_context_t *context,
const char *message,
bool is_hash);
-bool ui_display_address(dispatcher_context_t *dispatcher_context,
- const char *address,
- bool is_path_suspicious,
- const char *bip32_path_str);
-
bool ui_display_register_wallet_policy(
dispatcher_context_t *context,
const policy_map_wallet_header_t *wallet_header,
@@ -203,8 +197,6 @@ void set_ux_flow_response(bool approved);
*/
void ui_display_pubkey_flow(void);
-void ui_display_pubkey_suspicious_flow(void);
-
void ui_sign_message_and_confirm_flow(bool is_hash);
void ui_display_receive_in_wallet_flow(void);
diff --git a/src/ui/display_nbgl.c b/src/ui/display_nbgl.c
index d20b8bf..c6f188e 100644
--- a/src/ui/display_nbgl.c
+++ b/src/ui/display_nbgl.c
@@ -57,9 +57,6 @@ static nbgl_layoutTagValue_t pairs[N_UX_PAIRS];
static unsigned int n_pairs;
static nbgl_layoutTagValueList_t pairList;
-static nbgl_genericContents_t genericContent;
-static nbgl_content_t contentList[4];
-
extern bool G_was_processing_screen_shown;
static void finish_transaction_flow(bool choice);
@@ -140,18 +137,6 @@ static void start_transaction_callback(bool confirm) {
}
}
-static void generic_content_callback(int token, uint8_t index, int page) {
- UNUSED(index);
- UNUSED(page);
- switch (token) {
- case REVIEW_CONFIRM:
- status_operation_callback(true);
- break;
- default:
- PRINTF("Unhandled token : %d", token);
- }
-}
-
#define COMBINE(a, b) a b
// create the string "0 <coind_id> (self-transfer)"
@@ -400,72 +385,6 @@ void ui_display_register_wallet_policy_flow(void) {
status_operation_callback);
}
-void ui_display_pubkey_suspicious_flow(void) {
- confirmed_status = "Public key\napproved";
- rejected_status = "Public key rejected";
-
- pairs[0].item = "Path";
- pairs[0].value = g_ui_state.path_and_pubkey.bip32_path_str;
-
- pairs[1].item = "Public key";
- pairs[1].value = g_ui_state.path_and_pubkey.pubkey;
-
- // Setup list
- pairList.nbMaxLinesForValue = 0;
- pairList.nbPairs = 2;
- pairList.pairs = pairs;
-
- contentList[0].type = CENTERED_INFO;
- contentList[0].content.centeredInfo.icon = &ICON_APP_ACTION;
- contentList[0].content.centeredInfo.text1 = "Confirm public key";
- contentList[0].content.centeredInfo.text2 = NULL;
-#ifdef SCREEN_SIZE_WALLET
- contentList[0].content.centeredInfo.text3 = NULL;
- contentList[0].content.centeredInfo.style = LARGE_CASE_BOLD_INFO;
- contentList[0].content.centeredInfo.offsetY = 0;
-#else
- contentList[0].content.centeredInfo.style = BOLD_TEXT1_INFO;
-#endif
- contentList[0].contentActionCallback = NULL;
-
- contentList[1].type = CENTERED_INFO;
- contentList[1].content.centeredInfo.icon = &ICON_APP_IMPORTANT;
- contentList[1].content.centeredInfo.text1 = "WARNING";
- contentList[1].content.centeredInfo.text2 = "The derivation path\nis unusual";
-#ifdef SCREEN_SIZE_WALLET
- contentList[1].content.centeredInfo.text3 = NULL;
- contentList[1].content.centeredInfo.style = LARGE_CASE_BOLD_INFO;
- contentList[1].content.centeredInfo.offsetY = 0;
-#else
- contentList[1].content.centeredInfo.style = BOLD_TEXT1_INFO;
-#endif
- contentList[1].contentActionCallback = NULL;
-
- contentList[2].type = TAG_VALUE_LIST;
- memcpy(&contentList[2].content.tagValueList, &pairList, sizeof(nbgl_layoutTagValueList_t));
- contentList[2].contentActionCallback = NULL;
-
- contentList[3].type = INFO_BUTTON;
- contentList[3].content.infoButton.text = "Approve public key";
- contentList[3].content.infoButton.icon = &ICON_APP_ACTION;
-#ifdef SCREEN_SIZE_WALLET
- contentList[3].content.infoButton.buttonText = "Approve";
-#else
- contentList[3].content.infoButton.buttonText = "";
-#endif
- contentList[3].content.infoButton.buttonToken = REVIEW_CONFIRM;
-#ifdef HAVE_PIEZO_SOUND
- contentList[3].content.infoButton.tuneId = TUNE_TAP_CASUAL;
-#endif
- contentList[3].contentActionCallback = generic_content_callback;
-
- genericContent.callbackCallNeeded = false;
- genericContent.contentsList = contentList;
- genericContent.nbContents = 4;
-
- nbgl_useCaseGenericReview(&genericContent, "Cancel", status_operation_cancel);
-}
-
void ui_sign_message_and_confirm_flow(bool is_hash) {
pairs[0].item = "Path";
pairs[0].value = g_ui_state.path_and_message.bip32_path_str;
Why this scored 37/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.