update bip322 implementation to match completed spec
What changed, and why it matters
This commit adds a safety check when extracting a BIP-322 signature from a signed PSBT file. Before, Sparrow would blindly copy the signature into the dialog even if the message inside the PSBT did not match the message the user originally asked to sign. Now it warns the user and asks whether to continue, and if the user declines (or the extraction returns null), it no longer overwrites the signature field. This reduces the risk of a malicious or mismatched PSBT tricking a user into accepting a signature for a different message than intended.
Treat as a hardening/spec-compliance change rather than an active vulnerability. Users and reviewers should verify that getGenericSignedMessage() reliably returns the signed message for all supported output types and that the warning dialog cannot be bypassed by UI automation. Consider whether older releases should be noted as lacking this mismatch check.
Security signals we found
Added message-mismatch warning before extracting BIP-322 signature from PSBT
Prevents silent overwrite of signature field when PSBT message differs from dialog message
Null-check guards added at both PSBT signature extraction call sites
BIP-322 spec alignment mentioned in commit title
Evidence from the diff
The patch modifies MessageSignDialog.extractBip322Signature() to compare signedPsbt.getGenericSignedMessage() against the dialog’s message field. If they differ, a warning dialog is shown; only on YES does extraction proceed. Both call sites (direct result.psbt path and file-import path) now guard signature.clear()/appendText(sig) with if(sig != null). This prevents a mismatched or aborted PSBT from silently replacing the signature field. The change is defensive and aligns the BIP-322 implementation with the finalized spec, but the commit message does not frame it as a security fix.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/MessageSignDialog.javaBIP-322 message signing flowPSBT signature extractionInspect captured patch +19 / −5
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MessageSignDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/MessageSignDialog.java
index 3aa467d..59277cc 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MessageSignDialog.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MessageSignDialog.java
@@ -532,6 +532,16 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
}
private String extractBip322Signature(PSBT signedPsbt) {
+ String psbtMessage = signedPsbt.getGenericSignedMessage();
+ if(psbtMessage != null && !psbtMessage.equals(message.getText().trim())) {
+ Optional<ButtonType> response = AppServices.showWarningDialog("Message mismatch",
+ "The message in the signed PSBT does not match the message in this dialog.\n\nPSBT message: " + psbtMessage +
+ "\n\nContinue extracting the signature?", ButtonType.NO, ButtonType.YES);
+ if(response.isEmpty() || response.get() != ButtonType.YES) {
+ return null;
+ }
+ }
+
Wallet signingWallet = walletNode.getWallet();
if(signingWallet.getPolicyType() == PolicyType.SINGLE_SP) {
return Bip322.getBip322SignatureFromPsbtSp(signedPsbt);
@@ -565,8 +575,10 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
if(result.psbt != null) {
try {
String sig = extractBip322Signature(result.psbt);
- signature.clear();
- signature.appendText(sig);
+ if(sig != null) {
+ signature.clear();
+ signature.appendText(sig);
+ }
} catch(Exception e) {
log.error("Error extracting BIP-322 signature from PSBT", e);
AppServices.showErrorDialog("Error extracting signature", e.getMessage());
@@ -666,8 +678,10 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
byte[] psbtBytes = Files.readAllBytes(file.toPath());
PSBT signedPsbt = new PSBT(psbtBytes, false);
String sig = extractBip322Signature(signedPsbt);
- signature.clear();
- signature.appendText(sig);
+ if(sig != null) {
+ signature.clear();
+ signature.appendText(sig);
+ }
return;
} catch(Exception e) {
if(file.getName().toLowerCase(Locale.ROOT).endsWith(".psbt")) {
Why this scored 33/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.