ledger: throw on secret view key export rejection
What changed, and why it matters
This change hardens how the Monero wallet software talks to a Ledger hardware wallet. Previously, if the user rejected exporting the secret view key from the Ledger, the software silently accepted a fake placeholder key and continued with reduced functionality. Now the software throws a clear error and stops. This prevents a scenario where the wallet might proceed in a confused state after the user explicitly denied key export.
Treat this as a security hardening fix and include it in the next release. Users running Monero with Ledger should update. Review whether any other hardware wallet integrations have similar silent-fallback behavior on rejected key export.
Security signals we found
Replaces silent acceptance of a fake/placeholder secret view key with an explicit exception
Adds CHECK_AND_ASSERT_THROW_MES guard on user rejection during key export
Initializes sensitive key state to safe defaults (null_skey, false)
Prevents continued wallet operation after a rejected Ledger key export
Evidence from the diff
The patch modifies src/device/device_ledger.cpp and src/device/device_ledger.hpp. It replaces silent handling of a fake/placeholder view key with explicit exceptions. exchange_wait_on_input() now returns a status and CHECK_AND_ASSERT_THROW_MES ensures a non-zero return (user rejection) aborts with ‘Key export rejected on device.’ The view key member variables are also default-initialized (null_skey, false) to avoid uninitialized state. The change is defensive: it converts a silent fallback into a hard failure.
Changed components
src/device/device_ledger.cppsrc/device/device_ledger.hppLedger hardware wallet integration in MoneroInspect captured patch +11 / −12
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index bf5f614..91fb44a 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -410,7 +410,7 @@ namespace hw {
this->length_send = set_command_header_noopt(ins, p1);
if (ins == INS_GET_KEY && p1 == IO_SECRET_KEY) {
// export view key user input
- this->exchange_wait_on_input();
+ CHECK_AND_ASSERT_THROW_MES(this->exchange_wait_on_input() == 0, "Key export rejected on device.");
} else {
this->exchange();
}
@@ -619,15 +619,14 @@ namespace hw {
send_simple(INS_GET_KEY, 0x02);
//View key is retrievied, if allowed, to speed up blockchain parsing
- memmove(this->viewkey.data, this->buffer_recv+0, 32);
- if (is_fake_view_key(this->viewkey)) {
- MDEBUG("Have Not view key");
- this->has_view_key = false;
- } else {
- MDEBUG("Have view key");
- this->has_view_key = true;
- }
-
+ crypto::secret_key view_secret_key;
+ memmove(view_secret_key.data, this->buffer_recv+0, 32);
+
+ CHECK_AND_ASSERT_THROW_MES(!is_fake_view_key(view_secret_key), "Key export rejected on device.");
+
+ this->viewkey = view_secret_key;
+ this->has_view_key = true;
+
#ifdef DEBUG_HWDEVICE
send_simple(INS_GET_KEY, 0x04);
memmove(dbg_viewkey.data, this->buffer_recv+0, 32);
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index 9179e79..2634454 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -172,8 +172,8 @@ namespace hw {
HMACmap hmac_map;
// To speed up blockchain parsing the view key maybe handle here.
- crypto::secret_key viewkey;
- bool has_view_key;
+ crypto::secret_key viewkey = crypto::null_skey;
+ bool has_view_key = false;
device *controle_device;
Why this scored 56/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.