Merge pull request #10808 from SomberNight/202608_wallet_checksighash_handle_unknown
What changed, and why it matters
This change makes Electrum's wallet handle unusual or unrecognized Bitcoin signature hash types without crashing. Previously, if a transaction input used a sighash value not in the hardcoded list, the code would throw a KeyError exception. The patch now maps unknown sighash values to a warning labeled 'INSANE_SIGHASH'. This is a defensive hardening fix: it prevents an unexpected transaction from causing an unhandled error and instead reports it as a dangerous condition.
Treat as a minor hardening fix. Review whether unknown sighash should be rejected outright rather than merely warned, and ensure downstream callers handle TxSighashDanger consistently. No urgent action required unless users are processing untrusted partial transactions.
Security signals we found
Unhandled exception path in transaction validation replaced with explicit risk classification
Unknown sighash values now classified as INSANE_SIGHASH rather than crashing
Prevents potential denial-of-service or unexpected behavior from malformed or future sighash flags
No cryptographic weakness introduced; behavior is more conservative
Evidence from the diff
In electrum/wallet.py, check_sighash() builds a hintmap keyed by known sighash constants and then indexes it with sh_base and sh_acp derived from txin.sighash. Before the patch, any value not present in hintmap (e.g., an unknown or future sighash flag combination) caused a KeyError. The patch adds a fallback entry keyed by -1 for ‘unknown sighash’ and wraps the lookup in a try/except that falls back to this entry. The resulting risk level is INSANE_SIGHASH, which triggers a fatal warning/rejection path rather than an exception.
Changed components
electrum/wallet.pycheck_sighash methodPartialTransaction sighash validationInspect captured patch +7 / −2
### electrum/wallet.py
@@ -3469,6 +3469,7 @@ def check_sighash(self, tx: 'PartialTransaction') -> TxSighashDanger:
rl = TxSighashRiskLevel
hintmap = {
+ -1: (rl.INSANE_SIGHASH, _('Input {} is using an unknown sighash.')),
0: (rl.SAFE, None),
Sighash.NONE: (rl.INSANE_SIGHASH, _('Input {} is marked SIGHASH_NONE.')),
Sighash.SINGLE: (rl.WEIRD_SIGHASH, _('Input {} is marked SIGHASH_SINGLE.')),
@@ -3485,8 +3486,12 @@ def check_sighash(self, tx: 'PartialTransaction') -> TxSighashDanger:
sh_base = txin.sighash & (Sighash.ANYONECANPAY ^ 0xff)
sh_acp = txin.sighash & Sighash.ANYONECANPAY
for sh in [sh_base, sh_acp]:
- if msg := hintmap[sh][1]:
- risk_level = hintmap[sh][0]
+ try:
+ hint = hintmap[sh]
+ except KeyError:
+ hint = hintmap[-1] # "unknown sighash"
+ if msg := hint[1]:
+ risk_level = hint[0]
header = _('Fatal') if TxSighashDanger(risk_level=risk_level).needs_reject() else _('Warning')
shd = TxSighashDanger(
risk_level=risk_level,Why this scored 39/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.