Require exactly 32 bytes for PSBT_IN_PREVIOUS_TXID
What changed, and why it matters
This commit tightens validation of a Bitcoin transaction signing field. The Ledger app previously accepted any non-error value when reading the PSBT_IN_PREVIOUS_TXID field, even if it was shorter or longer than the required 32 bytes. Now it rejects any length other than exactly 32 bytes. An incorrect txid length could let a malformed or malicious PSBT misrepresent which previous transaction is being spent, potentially leading to signing the wrong transaction data.
Treat this as a security-hardening fix and include it in the next release. Review whether other PSBT map-value reads in the same file and related sign_psbt handlers also enforce exact expected lengths rather than just non-error returns. Consider adding test vectors with malformed PSBT_IN_PREVIOUS_TXID lengths (0, 31, 33, 64 bytes).
Security signals we found
Input validation bypass: length check was too permissive for a cryptographic identifier
PSBT parsing: previous txid field length not enforced to match SHA256d transaction hash size
Potential mismatch between claimed prevout and non-witness UTXO data
Patch is a strict length-equality fix, not a refactor
Evidence from the diff
In src/handler/sign_psbt/preprocess_inputs.c, the return-value check for call_get_merkleized_map_value() when fetching PSBT_IN_PREVIOUS_TXID changed from ‘0 > rc’ (any non-negative length accepted) to ‘32 != rc’ (exact length required). call_get_merkleized_map_value returns the number of bytes read on success or a negative error code on failure. The previous check therefore allowed values of 0-31 or 33+ bytes to be treated as valid. Because prevout_hash is a 32-byte buffer, a shorter read would leave uninitialized bytes and a longer read would be truncated, both breaking the intended equality check against the non-witness UTXO’s computed prevout hash.
Changed components
Ledger Bitcoin appsrc/handler/sign_psbt/preprocess_inputs.cPSBT signing flowPSBT_IN_PREVIOUS_TXID parsingInspect captured patch +6 / −6
### src/handler/sign_psbt/preprocess_inputs.c
@@ -168,12 +168,12 @@ bool __attribute__((noinline)) preprocess_inputs(
// check if the prevout_hash of the transaction matches the computed one from the
// non-witness utxo
- if (0 > call_get_merkleized_map_value(dc,
- &input.in_out.map,
- (uint8_t[]) {PSBT_IN_PREVIOUS_TXID},
- 1,
- prevout_hash,
- sizeof(prevout_hash))) {
+ if (32 != call_get_merkleized_map_value(dc,
+ &input.in_out.map,
+ (uint8_t[]) {PSBT_IN_PREVIOUS_TXID},
+ 1,
+ prevout_hash,
+ sizeof(prevout_hash))) {
SEND_SW(dc, SW_INCORRECT_DATA);
return false;
}Why this scored 65/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.