fix(core): allow text details memos in Bitcoin
What changed, and why it matters
This commit fixes a validation check in the Trezor hardware wallet's Bitcoin signing code. The device accepts 'payment request memos' that can contain different memo types, and it should reject requests where more than one type is set at once. A newly added memo type ('text details memo') was accidentally left out of the 'pick exactly one' check, so a malicious or buggy host could potentially include both a text memo and a text-details memo in the same payment request, confusing what the user sees or breaking an invariant the firmware relies on.
Treat as a security-relevant correctness fix. Review whether any other memo types or message fields are missing from similar exclusivity checks, and consider adding regression tests that exercise all combinations of memo fields.
Security signals we found
Input validation bypass
Missing field in mutually-exclusive check
Payment request memo type confusion
Potential UI/confirmation ambiguity
Evidence from the diff
In core/src/apps/bitcoin/sign_tx/helpers.py, _sanitize_payment_req counts how many memo fields are non-None and requires exactly one. The original tuple omitted memo.text_details_memo, so a PaymentRequestMemo could set text_memo and text_details_memo simultaneously (or combine text_details_memo with refund/coin_purchase) without triggering DataError. The patch adds text_details_memo to the tuple and changes the required None count from 2 to 3, matching the now four optional memo fields.
Changed components
core/src/apps/bitcoin/sign_tx/helpers.pyPaymentRequest memo sanitizationBitcoin transaction signing flowInspect captured patch +6 / −1
diff --git a/core/src/apps/bitcoin/sign_tx/helpers.py b/core/src/apps/bitcoin/sign_tx/helpers.py
index 35a29b46..c32efead 100644
--- a/core/src/apps/bitcoin/sign_tx/helpers.py
+++ b/core/src/apps/bitcoin/sign_tx/helpers.py
@@ -583,7 +583,12 @@ def _sanitize_tx_output(txo: TxOutput, coin: CoinInfo) -> TxOutput:
def _sanitize_payment_req(payment_req: PaymentRequest) -> PaymentRequest:
for memo in payment_req.memos:
- if (memo.text_memo, memo.refund_memo, memo.coin_purchase_memo).count(None) != 2:
+ if (
+ memo.text_memo,
+ memo.text_details_memo,
+ memo.refund_memo,
+ memo.coin_purchase_memo,
+ ).count(None) != 3:
raise DataError(
"Exactly one memo type must be specified in each PaymentRequestMemo."
)
Why this scored 38/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.