From 468853e436d3ceec0309557f057ca795426831e3 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Mon, 6 Jul 2026 02:00:47 -0500 Subject: [PATCH] psbt: reject trailing final witness data --- psbt/extractor.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/psbt/extractor.go b/psbt/extractor.go index cf7e7b66..6d2d00f3 100644 --- a/psbt/extractor.go +++ b/psbt/extractor.go @@ -46,24 +46,24 @@ func Extract(p *Packet) (*wire.MsgTx, error) { // to extract that as well, parsing the lower-level transaction // encoding. if pInput.FinalScriptWitness != nil { - // In order to set the witness, need to re-deserialize - // the field as encoded within the PSBT packet. For - // each input, the witness is encoded as a stack with - // one or more items. + // PSBT_IN_FINAL_SCRIPTWITNESS stores the complete + // scriptWitness for this transaction input. Decode that + // single serialized witness stack into TxWitness below. witnessReader := bytes.NewReader( pInput.FinalScriptWitness, ) - // First we extract the number of witness elements - // encoded in the above witnessReader. + // First extract the number of witness items encoded in + // the serialized scriptWitness. witCount, err := wire.ReadVarInt(witnessReader, 0) if err != nil { return nil, err } - // Now that we know how many inputs we'll need, we'll - // construct a packing slice, then read out each input - // (with a varint prefix) from the witnessReader. + // Allocate one slot per witness item, then read each + // varint-prefixed item from the witness value. The value + // must contain exactly this one stack, so the exhaustion + // check below rejects trailing bytes. tin.Witness = make(wire.TxWitness, witCount) for j := uint64(0); j < witCount; j++ { wit, err := wire.ReadVarBytes( @@ -75,6 +75,10 @@ func Extract(p *Packet) (*wire.MsgTx, error) { } tin.Witness[j] = wit } + + if err := assertFullyConsumed(witnessReader); err != nil { + return nil, err + } } }