What changed, and why it matters
This commit changes how the 'decoderawtransaction' RPC command reads raw transaction bytes. Previously it used a looser deserialization method that could accept data beyond the end of the transaction. Now it uses a stricter parser that rejects trailing extra bytes. The likely security relevance is preventing malformed or padded transaction blobs from being accepted as valid, which could otherwise mislead wallets, explorers, or downstream services that rely on this RPC output.
Treat as a hardening fix. Review whether any other RPC handlers or internal callers still use the permissive wire.MsgTx.Deserialize pattern on untrusted input, and consider adding regression tests for decoderawtransaction with trailing bytes.
Security signals we found
Stricter input validation on an RPC endpoint
Replacement of permissive deserialization with exact-length parsing
Potential for transaction malleability / ambiguity if trailing bytes were previously ignored
Evidence from the diff
handleDecodeRawTransaction in rpcserver.go switched from wire.MsgTx.Deserialize(bytes.NewReader(serializedTx)) to btcutil.NewTxFromBytes(serializedTx). The old wire deserialization only parses the transaction and ignores trailing bytes, while btcutil.NewTxFromBytes is documented to require the byte slice to contain exactly one transaction. The change therefore makes the RPC reject inputs with appended/prefixed garbage. The rest of the function is unchanged except for adapting to the new return type (tx.MsgTx()).
Changed components
rpcserver.gohandleDecodeRawTransactiondecoderawtransaction RPCInspect captured patch +4 / −4
diff --git a/rpcserver.go b/rpcserver.go
index 35c7f52..7decabd 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -791,22 +791,22 @@ func handleDecodeRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan
if err != nil {
return nil, rpcDecodeHexError(hexStr)
}
- var mtx wire.MsgTx
- err = mtx.Deserialize(bytes.NewReader(serializedTx))
+ tx, err := btcutil.NewTxFromBytes(serializedTx)
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCDeserialization,
Message: "TX decode failed: " + err.Error(),
}
}
+ mtx := tx.MsgTx()
// Create and return the result.
txReply := btcjson.TxRawDecodeResult{
Txid: mtx.TxHash().String(),
Version: mtx.Version,
Locktime: mtx.LockTime,
- Vin: createVinList(&mtx),
- Vout: createVoutList(&mtx, s.cfg.ChainParams, nil),
+ Vin: createVinList(mtx),
+ Vout: createVoutList(mtx, s.cfg.ChainParams, nil),
}
return txReply, nil
}
Why this scored 45/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.