Bitcoin Sighash Types and Multisig Malleability Resistance

You've just watched a transaction broadcast. Three hardware devices, two lawyers, one cold storage setup that consumed your entire weekend to configure correctly. It signed. It propagated. And then, before a single confirmation lands, something mutates it. Not the amount. Not the recipient. Just enough of the serialized transaction data that the txid changes, and any downstream logic watching for that specific identifier breaks. Silently.

That's transaction malleability. The sighash type you chose when constructing those signatures is either your first line of defense or the precise reason it happened.

What a Sighash Flag Actually Commits To

Every Bitcoin signature doesn't just sign "this transaction." It signs a specific serialized digest, and the sighash flag is the instruction that determines which parts get included in that digest. Change what's committed to, and you change what a third party can modify without invalidating the signature.

Bitcoin has had six sighash types since the early protocol days. `SIGHASH_ALL` (0x01) commits to every input and every output. `SIGHASH_NONE` (0x02) commits to inputs but no outputs whatsoever. `SIGHASH_SINGLE` (0x03) commits each input to its corresponding output by index. Each can be combined with `SIGHASH_ANYONECANPAY` (0x80), which strips the commitment down to just the one input being signed, leaving all other inputs open for modification.

For a simple single-sig payment, `SIGHASH_ALL` is so standard it barely warrants a mention. Multisig is where the choice starts to sting.

Consider a Lightning-adjacent payment channel construction: Alice and Bob open a 2-of-2 multisig funding output. Their commitment transactions must be pre-signed before the funding transaction ever broadcasts. If either party uses `SIGHASH_SINGLE` carelessly, and the output index doesn't match the input index being signed, Bitcoin's protocol historically returned a value of 1 (the "off-by-one" bug, documented in the codebase). That 1 gets signed. The signature is technically valid. The commitment is meaningless, and the channel can be drained.

That scenario is not theoretical. It was a documented edge case that protocol engineers worked around explicitly when designing the Lightning Network's funding flow, and the fact that it required an explicit workaround tells you something about how quietly these bugs operate.

The Malleability Surface in Multisig

Multisig adds its own wrinkle. In a standard P2SH or bare multisig construction using legacy transaction formats, a third party (a miner, a relay node, anyone in the propagation path) can sometimes modify the scriptSig without touching the signatures themselves. They can add extra data, reorder the dummy element that legacy OP_CHECKMULTISIG requires due to a known off-by-one bug, or pad the push operations. The txid changes. Your signatures remain valid. Your monitoring breaks.

Legacy malleability in this context works less like a targeted attack and more like rust: it accumulates in the joints of complex constructions until something load-bearing gives way.

SegWit (BIP141) addressed the legacy malleability surface by moving witness data outside the txid commitment entirely. A P2WSH 2-of-3 multisig uses the witness field for signatures; the txid is computed without it. Mutate the witness, the txid doesn't change. This is the core reason Lightning requires SegWit inputs for funding transactions, full stop.

But SegWit doesn't make sighash selection irrelevant. It introduced its own digest algorithm (BIP143) that commits to the input's value directly, closing a separate class of attacks where a hardware signer couldn't verify the amount being spent without trusting the host. For multisig hardware wallets, that input-value commitment isn't cosmetic. It's what lets a Ledger or Trezor display an accurate fee without trusting the coordinator.

Taproot (BIP341) goes further still. Tapscript signatures commit to all input amounts and all scriptPubKeys simultaneously by default. In a MuSig2 threshold construction, that means a partially-signing participant cannot be tricked into signing a digest that understates fees or misrepresents the UTXO set. The sighash digest is richer, and the malleability surface shrinks accordingly.

Are you reviewing a multisig descriptor someone else wrote? If you're looking at a P2SH address with no SegWit wrapping, you're looking at a construction that carries the full legacy malleability risk. That doesn't mean funds are at risk of theft directly. It means txid stability isn't guaranteed, and any covenant logic or payment channel built on top of it is standing on loose ground, the kind that holds until it doesn't.

The practical lesson is not complicated, even if the protocol mechanics are. Sighash type selection is a commitment about trust boundaries, and treating it as a minor implementation detail is a mistake. `SIGHASH_ALL` in a P2WSH or P2TR context is conservative and correct for almost every multisig use case. Anything more exotic: `SIGHASH_NONE`, `ANYONECANPAY` combinations, or `SIGHASH_SINGLE` without careful index accounting, opens surface area that only makes sense if you've explicitly designed the construction to require it and can defend that design choice in writing.

The engineers who built CoinJoin coordinators and PSBT-based collaborative transaction protocols spent considerable time mapping exactly which participants could modify which fields after partial signing. That discipline isn't overcaution. It's the work that keeps complex constructions from quietly failing the one time it actually matters.