#35358 external signer: verify PSBT is reliable after signing it
https://github.com/bitcoin/bitcoin/pull/35358 · · +264/-16 in 4 files, 1 commits · labels: none
Goal
- Protect wallet users from buggy or malicious external signers altering transaction outputs
- Ensure signed transactions match expected outputs and do not introduce weak signature hashes
Adds a post-signing validation pass in `ExternalSigner::SignTransaction` that compares the signed PSBT against the original PSBT before accepting it. It checks that output counts, amounts, and scripts match, and verifies that no unsafe sighash types (such as SIGHASH_NONE or SIGHASH_SINGLE) were introduced. It also adds mock and functional test coverage in `wallet_signer.py` and `rpc_signer.py`.
Problem: Bitcoind previously accepted signed PSBTs returned by external signers without checking whether outputs were modified or whether weak sighash flags were attached, leaving users vulnerable to rogue or buggy signer software altering transaction details.
Category: Wallet (#82 of 84)
P3 · fund safety
- P3 because it provides defense in depth against compromised or buggy hardware signers mutating outputs
- Benefit is marginal because external signers are already trusted to present output details to users
Verifying that external signers did not mutate outputs or inject weak sighash flags provides defense-in-depth against malicious or buggy external signer software. It is ranked P3 because hardware signers are generally trusted to present output data on-device, making this a secondary safety invariant rather than a fix for an active vulnerability.
Membership: Touches external signer transaction verification in `src/external_signer.cpp` and wallet signer tests.
Factors: security/stability 1, bug 0, performance 0, user value 1, leverage 0
Reviewability: Stale: Review #36114 instead
The author has been inactive for 118 days, exceeding the 60-day project staleness threshold, and Sjors has absorbed the patch into #36114.
Author status: silent since 2026-05-22
Resolved concerns:
- junbyjun1238 asked whether SIGHASH_ANYONECANPAY combined with SIGHASH_ALL should be permitted; achow101 clarified that it remains safe because the wallet's inputs and outputs remain committed to.
Agreement: Positive
- Mild concept approval with skepticism over whether signers need verification (achow101)
- Absorbed the implementation into #36114 to improve signer test mocking (Sjors)
Positive; achow101 gave mild concept support, and Sjors absorbed the change into #36114
achow101 offered concept approval with mild skepticism about the threat model, while Sjors adopted the implementation directly into PR #36114.
- achow101 commented: 'Concept OK I guess... I think we generally assume an external signer to be more trusted/secure, so we don't really do checks on their output.'
- Sjors commented: 'I absorbed this into #36114, which revamps the external signer mock in a way that makes this stuff easier to test.'
Review verdicts (DrahtBot): 0
Dependencies
Enables:
Files
223 lines under test/bench/ci.
- test/functional/mocks/signer.py +78/-5
- test/functional/rpc_signer.py +72/-0
- test/functional/wallet_signer.py +57/-11
- src/external_signer.cpp +57/-0
Card
Adds output and sighash invariant validation in ExternalSigner::SignTransaction to ensure external signers cannot alter outputs or attach SIGHASH_NONE. Protects wallet users utilizing hardware or external signers from buggy or rogue signer bridges. achow101 provided concept support noting signers are already considered trusted, while Sjors integrated the patch into #36114. Further review on this PR is unnecessary because the author is inactive and the code has been absorbed into #36114.