SFT-7133: fixed dangerous change check on all taproot inputs
What changed, and why it matters
This firmware update fixes a bug in how Passport checks whether a Bitcoin transaction's 'change' output is safe to send back to the user's own wallet. For modern Taproot-style transactions, the device was skipping an important ownership check on inputs. That could let a malicious or crafted PSBT (Partially Signed Bitcoin Transaction) trick the user into treating someone else's coins as their own change, potentially approving a transaction that sends funds to an attacker while the screen says it is just change.
Treat this as a security-relevant bug fix and include it in the next firmware release. Users signing Taproot transactions should update. Review related PSBT validation paths to ensure no other subpath checks omit tap_subpaths. Consider adding regression tests for dangerous_change_check with Taproot inputs.
Security signals we found
dangerous change check bypass on Taproot inputs
missing validation path for tap_subpaths
PSBT input ownership verification gap
single-character logic fix in security-critical code
Taproot-specific security control failure
Evidence from the diff
In psbtObject.dangerous_change_check(), the code iterates over transaction inputs and skips any input that lacks subpaths. The original condition only checked inp.subpaths, so for Taproot inputs where ownership derivation is stored in inp.tap_subpaths, the input was skipped entirely. The patch adds ‘and not inp.tap_subpaths’ so that Taproot inputs with derivation information are also validated. Skipping the check means the function may fail to verify that all inputs belong to the same seed/derivation as the change output, weakening the dangerous-change detection for Taproot transactions.
Changed components
ports/stm32/boards/Passport/modules/psbt.pypsbtObject.dangerous_change_check()Taproot input handlingInspect captured patch +1 / −1
diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py
index d703256..1fe3b53 100644
--- a/ports/stm32/boards/Passport/modules/psbt.py
+++ b/ports/stm32/boards/Passport/modules/psbt.py
@@ -1301,7 +1301,7 @@ class psbtObject(psbtProxy):
continue
if not inp.required_key:
continue
- if not inp.subpaths:
+ if not inp.subpaths and not inp.tap_subpaths:
continue # not expected if we're signing it
paths = []
if inp.subpaths:
Why this scored 70/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.