fix: Empty SIGN_MESSAGE request displays uninitialized stack memory
What changed, and why it matters
This commit fixes a bug where signing an empty Bitcoin message could cause the Ledger device to display random leftover data from its memory instead of a clean empty message. The fix simply ensures the message buffer starts as an empty string before any data is copied into it. This is an information disclosure issue: an attacker who can trigger an empty message signing request might get the device to show uninitialized stack memory on screen. It does not appear to allow stealing coins directly, but it is a security-relevant bug in a trusted display path.
Treat as a low-to-moderate security fix. Review whether other handlers use similar uninitialized buffers before display, and ensure the fix is included in the next firmware release. No immediate emergency response is warranted because exploitation requires user interaction with a crafted signing request and only leaks memory contents to the screen.
Security signals we found
Uninitialized stack variable used in UI display path
Information disclosure via trusted device screen
Fix is minimal and directly addresses root cause
No bounds-checking or memory-safety changes beyond initialization
Evidence from the diff
In src/handler/sign_message.c, handler_sign_message() declares a stack buffer message_full[MAX_DISPLAYBLE_MESSAGE_LENGTH + 1] and then copies message chunks into it. If message_length is 0, the loop that copies chunks does not execute, leaving the buffer uninitialized. The display logic later reads this buffer, so the user could be shown uninitialized stack memory. The patch adds message_full[0] = ‘\0’; immediately after declaration, guaranteeing a well-terminated empty string when no chunks are copied. The bug is local to the sign-message handler and is triggered by a zero-length SIGN_MESSAGE request.
Changed components
src/handler/sign_message.cSIGN_MESSAGE APDU handlerdevice message display UIInspect captured patch +1 / −0
diff --git a/src/handler/sign_message.c b/src/handler/sign_message.c
index 89e3341..8db9583 100644
--- a/src/handler/sign_message.c
+++ b/src/handler/sign_message.c
@@ -83,6 +83,7 @@ void handler_sign_message(dispatcher_context_t *dc, uint8_t protocol_version) {
}
uint8_t message_full[MAX_DISPLAYBLE_MESSAGE_LENGTH + 1];
+ message_full[0] = '\0';
size_t n_chunks = (message_length + MESSAGE_CHUNK_SIZE - 1) / MESSAGE_CHUNK_SIZE;
for (unsigned int i = 0; i < n_chunks; i++) {
uint8_t *message_chunk = &message_full[i * MESSAGE_CHUNK_SIZE * not_long_message];
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.