What changed, and why it matters
This commit adds a new test to the btcd PSBT (Partially Signed Bitcoin Transaction) library. The test checks that when extracting a final Bitcoin transaction from a PSBT, the library rejects a final witness value that has extra trailing bytes after a valid witness stack. Previously, this trailing data might have been silently accepted, which could lead to non-standard or invalid transactions being produced. The commit itself only adds a test, not a fix, so it implies a prior or pending code change that enforces this rejection.
Verify that the production Extract implementation already rejects trailing final witness data as tested; if not, apply the corresponding fix. Review related PSBT parsing paths for similar leniency issues. Run the new test and the full psbt test suite.
Security signals we found
Strict parsing of final witness data to reject malformed/trailing bytes
Prevents creation of transactions with non-standard witness encoding
Test-only commit implies behavior enforcement elsewhere in the codebase
Evidence from the diff
The change introduces TestExtractRejectsTrailingFinalScriptWitnessData in psbt/psbt_test.go. It constructs a PSBT Packet with a single input whose FinalScriptWitness is a valid serialized witness stack (one element, 0x51) followed by an extra trailing 0x00 byte. The test asserts that Extract(packet) returns ErrInvalidPsbtFormat. This validates that the extractor strictly parses the final script witness and rejects trailing data, ensuring only exactly one serialized witness stack is accepted per input.
Changed components
btcd/psbt packagePSBT extraction logic (Extract function)FinalScriptWitness handlingInspect captured patch +26 / −0
diff --git a/psbt/psbt_test.go b/psbt/psbt_test.go
index 8b8b3a6..0d5f907 100644
--- a/psbt/psbt_test.go
+++ b/psbt/psbt_test.go
@@ -787,6 +787,32 @@ func TestPsbtExtractor(t *testing.T) {
}
}
+// TestExtractRejectsTrailingFinalScriptWitnessData ensures a final witness
+// value must contain exactly one serialized witness stack.
+func TestExtractRejectsTrailingFinalScriptWitnessData(t *testing.T) {
+ tx := wire.NewMsgTx(2)
+ tx.AddTxIn(wire.NewTxIn(&wire.OutPoint{}, nil, nil))
+ tx.AddTxOut(wire.NewTxOut(0, []byte{0x6a}))
+
+ var witness bytes.Buffer
+ err := WriteTxWitness(&witness, [][]byte{{0x51}})
+ require.NoError(t, err)
+
+ finalWitness := append([]byte{}, witness.Bytes()...)
+ finalWitness = append(finalWitness, 0x00)
+
+ packet := &Packet{
+ UnsignedTx: tx,
+ Inputs: []PInput{{
+ FinalScriptWitness: finalWitness,
+ }},
+ Outputs: []POutput{{}},
+ }
+
+ _, err = Extract(packet)
+ require.ErrorIs(t, err, ErrInvalidPsbtFormat)
+}
+
func TestFinalizerAddSigHashFlags(t *testing.T) {
var signedPsbtData = map[string]string{
"Default": "70736274ff01005e0200000001f1aabce974f1b242b36913f4f8a9f138a8042914dddc4117a578813a4dc32ee10000000000ffffffff017b0a0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b430b0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1011340e80246ac1955def419572514e50e4be47f56ccd51beae41ec80ad30cb77ed59ebca3c38dd8506e1b7c28fafa4bdf7d821464be1ee152416bdaf2c056fb4fb3290117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
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.