What changed, and why it matters
This commit fixes a type mismatch in the Ledger Bitcoin app's swap verification code. The lengths of Bitcoin addresses were being stored in small signed/char variables instead of the proper unsigned size type. For extremely long strings this could in theory cause the comparison to misbehave, but in practice Bitcoin addresses are short enough that the bug is unlikely to be exploitable. It is a hardening fix rather than a clear vulnerability.
Treat as a defensive hardening patch. Review whether any other length variables in the swap/signing path use narrow signed types, and add static-analysis rules to flag strlen() assigned to non-size_t types.
Security signals we found
Type conversion fix in security-critical swap address comparison
Use of signed/char type for strlen() return value
Potential bypass of app-exchange destination-address verification
Evidence from the diff
In execute_swap_checks(), strlen() results were assigned to char and int variables. The patch changes them to size_t and updates the loop indices accordingly. strlen() returns size_t; storing it in a signed char truncates the value and can make negative comparisons behave unexpectedly. The affected code compares the swap destination address from app-exchange against the PSBT output address; a length mismatch or wrong comparison could cause the swap safety check to pass or fail incorrectly.
Changed components
src/handler/sign_psbt.cexecute_swap_checks()Ledger app-exchange swap flowInspect captured patch +4 / −4
diff --git a/src/handler/sign_psbt.c b/src/handler/sign_psbt.c
index a2eca99..c323c79 100644
--- a/src/handler/sign_psbt.c
+++ b/src/handler/sign_psbt.c
@@ -1167,22 +1167,22 @@ execute_swap_checks(dispatcher_context_t *dc, sign_psbt_state_t *st) {
finalize_exchange_sign_transaction(false);
}
- char output_description_len = strlen(output_description);
+ size_t output_description_len = strlen(output_description);
// Check that the external output's address matches the request from app-exchange
- int swap_addr_len = strlen(G_swap_state.destination_address);
+ size_t swap_addr_len = strlen(G_swap_state.destination_address);
if (swap_addr_len != output_description_len ||
0 !=
strncmp(G_swap_state.destination_address, output_description, output_description_len)) {
// address did not match
PRINTF("Mismatching address for swap\n");
PRINTF("Expected: ");
- for (int i = 0; i < swap_addr_len; i++) {
+ for (size_t i = 0; i < swap_addr_len; i++) {
PRINTF("%c", G_swap_state.destination_address[i]);
}
PRINTF("\n");
PRINTF("Found: ");
- for (int i = 0; i < output_description_len; i++) {
+ for (size_t i = 0; i < output_description_len; i++) {
PRINTF("%c", output_description[i]);
}
PRINTF("\n");
Why this scored 41/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.