Abort if input/output amounts are absurd
What changed, and why it matters
This commit adds safety checks in the Ledger Bitcoin app's transaction signing code. Before this change, the app would continue processing Bitcoin transaction inputs and outputs even if their amounts were larger than all the Bitcoin that will ever exist. Such absurdly large values could potentially cause arithmetic overflows in later calculations. The fix makes the app immediately reject these transactions with an error instead of continuing.
Review whether other amount accumulations in the signing flow (e.g., fee computation, change detection, total_amount) are also protected against overflow, and consider whether the 21M BTC bound is the appropriate guard for all downstream arithmetic.
Security signals we found
Integer overflow prevention
Input validation hardening
Defensive bounds checking on monetary amounts
Commit message describes security-relevant motivation
Evidence from the diff
In src/handler/sign_psbt.c, two sanity checks were added to preprocess_inputs() and preprocess_outputs(). Each now validates that the prevout_amount (input) and output value do not exceed 21,000,000 BTC (in satoshis: 21000000 * 100000000). If exceeded, the handler sends SW_INCORRECT_DATA and aborts. The commit message explicitly states the purpose is to avoid integer overflows during the signing flow, even though such transactions would be invalid on-chain anyway.
Changed components
src/handler/sign_psbt.cpreprocess_inputs()preprocess_outputs()Inspect captured patch +14 / −0
diff --git a/src/handler/sign_psbt.c b/src/handler/sign_psbt.c
index 6908296..6de94a1 100644
--- a/src/handler/sign_psbt.c
+++ b/src/handler/sign_psbt.c
@@ -739,6 +739,13 @@ preprocess_inputs(dispatcher_context_t *dc,
}
}
+ if (input.prevout_amount > 21000000ULL * 100000000ULL) {
+ // sanity check to avoid overflows in amounts
+ PRINTF("Input amount exceed Bitcoin total supply!\n");
+ SEND_SW(dc, SW_INCORRECT_DATA);
+ return false;
+ }
+
// check if the input is internal; if not, continue
int is_internal = is_in_out_internal(dc, st, sign_psbt_cache, &input.in_out, true);
@@ -956,6 +963,13 @@ preprocess_outputs(dispatcher_context_t *dc,
}
uint64_t value = read_u64_le(raw_result, 0);
+ if (value > 21000000ULL * 100000000ULL) {
+ // sanity check to avoid overflows in amounts
+ PRINTF("Output amount exceed Bitcoin total supply!\n");
+ SEND_SW(dc, SW_INCORRECT_DATA);
+ return false;
+ }
+
output.value = value;
st->outputs.total_amount += value;
Why this scored 59/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.