Make sure raw_witnessUtxo is long enough before reading its 9th byte
What changed, and why it matters
This commit fixes a length check in the Ledger Bitcoin app's PSBT signing code. Before reading the 9th byte of a witness UTXO field, the code now verifies the field is at least 9 bytes long. Previously, it only checked that some data was returned, which could lead to reading past the end of a malformed or truncated input. This is a defensive fix against an out-of-bounds read that could affect transaction amount calculations during signing.
Treat this as a security-relevant hardening fix. Review related PSBT parsing functions for similar insufficient-length checks, and include this patch in the next firmware release. If a CVE is desired, request one from a CNA; no CVE is present in the commit materials.
Security signals we found
Out-of-bounds read prevented by length check
PSBT witness UTXO parsing hardening
Memory safety fix in cryptographic signing path
Potential denial-of-service or information disclosure via malformed PSBT
Evidence from the diff
In amount_from_psbt.c, the function get_amount_scriptpubkey_from_psbt_witness reads a witness UTXO from a PSBT. The format is an 8-byte amount followed by a length-prefixed scriptPubkey, with the scriptPubkey length stored at byte offset 8. The original check wit_utxo_len < 0 only rejected negative lengths (errors), but allowed zero- to 8-byte buffers. The patch changes the minimum accepted length to 8 + 1 bytes, ensuring raw_witnessUtxo[8] is always within bounds. This prevents an out-of-bounds read when parsing a malformed PSBT witness UTXO entry.
Changed components
src/handler/sign_psbt/amount_from_psbt.cLedger Bitcoin app PSBT signing flowwitness UTXO amount extractionInspect captured patch +4 / −1
diff --git a/src/handler/sign_psbt/amount_from_psbt.c b/src/handler/sign_psbt/amount_from_psbt.c
index 3b6ebcc..a377535 100644
--- a/src/handler/sign_psbt/amount_from_psbt.c
+++ b/src/handler/sign_psbt/amount_from_psbt.c
@@ -81,7 +81,10 @@ get_amount_scriptpubkey_from_psbt_witness(dispatcher_context_t *dc,
raw_witnessUtxo,
sizeof(raw_witnessUtxo));
- if (wit_utxo_len < 0) {
+ // the witness UTXO field is encoded as 8-bytes for the amount, followed by the length-prefixed
+ // scriptPubkey. We make sure that we can read at least up to the scriptPubkey length, to avoid
+ // reading a possibly-undefined byte at offset 8.
+ if (wit_utxo_len < 8 + 1) {
return -1;
}
int wit_utxo_scriptPubkey_len = raw_witnessUtxo[8];
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.