CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-117601

CVE-2026-117601: Improper Cryptographic Signature Verification in Electrum Bitcoin Wallet

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 28, 2026·10 min read·9 visits

Executive Summary (TL;DR)

Electrum Bitcoin Wallet versions prior to 4.8.3 fail to verify cryptographic signatures on wallet-owned inputs for unconfirmed transactions received from Electrum servers. A malicious server can inject a spoofed, zero-fee mempool transaction spending the user's funds to an attacker address and induce the user to sign it via a Replace-By-Fee (RBF) fee bump.

A missing cryptographic signature verification vulnerability exists in Electrum Bitcoin Wallet versions prior to 4.8.3. In Electrum's Simplified Payment Verification (SPV) architecture, the client failed to validate input signatures on unconfirmed mempool transactions received from connected Electrum servers. A malicious Electrum server can exploit this flaw by intercepting a legitimate user broadcast, suppressing it, and returning a spoofed unconfirmed transaction with an invalid signature and zero fee that redirects the user's UTXOs to an attacker-controlled address. When the user initiates a Replace-By-Fee (RBF) action to accelerate the seemingly stuck transaction, Electrum signs the spoofed outputs with the user's private keys, resulting in the direct theft of funds.

Vulnerability Overview

Electrum is a widely deployed lightweight Bitcoin wallet that operates under the Simplified Payment Verification (SPV) client-server architecture. Rather than downloading and indexing the full Bitcoin blockchain locally, Electrum clients connect over TLS/TCP via JSON-RPC to external Electrum servers (such as ElectrumX, Fulcrum, or Electrs) to retrieve address histories, unspent transaction outputs (UTXOs), and unconfirmed mempool states.

In versions prior to 4.8.3, Electrum contains an improper verification of cryptographic signature vulnerability (CWE-347) within its transaction synchronization subsystem (AddressSynchronizer). While confirmed transactions are cryptographically verified against block header Merkle roots and proof-of-work difficulty chains, unconfirmed transactions residing in the mempool lack block inclusion proofs. Prior to the patch, Electrum accepted raw unconfirmed transactions from the connected server and inserted them directly into the local wallet database without verifying whether the transaction inputs possessed valid cryptographic signatures.

This architectural oversight exposes users connected to untrusted or compromised Electrum servers to transaction state manipulation. By returning crafted mempool data via the blockchain.scripthash.get_history and blockchain.transaction.get RPC methods, a malicious server can inject arbitrary unconfirmed transactions that purport to spend the user's own coins (is_mine inputs).

When combined with Bitcoin's Replace-By-Fee (BIP 125) mechanism, this state pollution enables an attacker to hijack legitimate outgoing payments. The attacker server suppresses a user's valid transaction broadcast, substitutes an invalid transaction paying the attacker with a zero or negligible fee, and relies on the user invoking the wallet's fee-bumping utility to generate a valid cryptographic signature over the attacker's outputs.

Root Cause Analysis

The root cause of CVE-2026-117601 lies in the asymmetry between how Electrum validates confirmed versus unconfirmed transactions in electrum/address_synchronizer.py. When a transaction is confirmed in a block, its validity is guaranteed by the cumulative proof-of-work of the block header and the corresponding Merkle branch proof verified by the SPV client. However, unconfirmed transactions exist only in the mempool, meaning the light client cannot rely on block headers to prove that a full node has validated the transaction's script execution and ECDSA/Schnorr signatures.

Prior to version 4.8.3, AddressSynchronizer.add_transaction() parsed raw transaction hex received from the server and immediately updated the internal UTXO and transaction history tables (self.db). The method did not inspect the scriptSig or witness fields of transaction inputs spending outputs owned by the wallet. Consequently, a transaction containing empty, malformed, or arbitrary signature bytes was treated as a legitimate pending spend in the wallet's state machine and user interface.

Once an invalid transaction (Tx2) spending a wallet-owned UTXO is recorded in self.db, it marks that specific outpoint as spent and displays the transaction in the client's History tab. Because the client trusts the server's representation of the mempool, the user sees an unconfirmed transaction with the parameters specified by the server, including its fee rate and output destinations.

The critical failure occurs when the user interacts with this polluted state through the Replace-By-Fee (RBF) workflow. When a user selects "Bump Fee" on an unconfirmed transaction, Electrum retrieves the stored transaction object from the local database, clones its inputs and outputs, adjusts the fee deduction or attaches additional inputs, and passes the resulting PartialTransaction to wallet.sign_transaction(). Because the wallet constructs the replacement transaction directly from the unverified Tx2 template, signing the replacement produces a fully valid, network-broadcastable transaction that sends the user's funds to the attacker's outputs.

Code Analysis

The vulnerability was resolved in commit 90fe30822561e515a9d2d6e5a352cc07780999eb by introducing explicit cryptographic signature verification for all unconfirmed transaction inputs owned by the wallet, alongside a staging mechanism for transactions claimed to be mined.

First, the patch defines a dedicated exception InvalidTxSignature in electrum/util.py and integrates an input verification gate within AddressSynchronizer.add_transaction() in electrum/address_synchronizer.py. When a transaction is added, the synchronizer checks whether all inputs spending wallet-owned UTXOs contain valid signatures:

# electrum/address_synchronizer.py
# check signatures of inputs spending our coins
stored_tx = self.db.get_transaction(tx_hash)
is_new_witness = stored_tx is None or isinstance(stored_tx, PartialTransaction)
checked_tx = tx if is_new_witness else stored_tx  # db keeps a complete tx
if not self._are_new_inputs_valid(checked_tx, range(len(tx.inputs())), is_new_witness=is_new_witness):
    if not is_new_witness:
        self.remove_transaction(tx_hash)
    raise InvalidTxSignature()

The helper method _are_new_inputs_valid() iterates over the transaction inputs, filters for non-coinbase inputs matching self.is_mine(addr), locates the parent transaction (prev_tx) in the local database, and invokes the self.verify_txins callback if the transaction is not already SPV-verified:

# electrum/address_synchronizer.py
def _are_new_inputs_valid(
        self, tx: Transaction, txin_idxs: Iterable[int], *, prev_tx: Transaction = None, is_new_witness: bool,
) -> bool:
    if self.verify_txins is None or not tx.is_complete():
        return True
    if isinstance(tx, PartialTransaction):
        tx = Transaction(tx.serialize())  # input addresses from our db, not from the psbt
    if self.db.is_in_verified_tx(tx.txid()):
        return True  # mined
    prev_txs = {}
    for txin_idx in txin_idxs:
        txin = tx.inputs()[txin_idx]
        if txin.is_coinbase_input():
            continue
        addr = self.get_txin_address(txin)
        if not self.is_mine(addr):
            continue
        txin_prev_tx = prev_tx or self.db.get_transaction(txin.prevout.txid.hex())
        if txin_prev_tx is None:
            continue  # checked when prev_tx is added
        if not is_new_witness and txin.prevout.to_str() in dict(self.db.get_txi_addr(tx.txid(), addr)):
            continue
        prev_txs[txin_idx] = txin_prev_tx
    return not prev_txs or self.verify_txins(tx, prev_txs)

The core cryptographic check is implemented in electrum/wallet.py via _verify_txin_signatures(). This method converts the transaction into a PartialTransaction, attaches the parent output (witness_utxo) and local script descriptor to each wallet-owned input, extracts DER-encoded signatures from the witness and scriptSig, and verifies each signature against the wallet's public keys using ptx.verify_sig_for_txin():

# electrum/wallet.py
def _verify_txin_signatures(self, tx: Transaction, prev_txs: Mapping[int, Transaction]) -> bool:
    if isinstance(tx, PartialTransaction):
        tx = Transaction(tx.serialize())
    ptx = PartialTransaction.from_tx(tx)
    sighash_cache = SighashCache()
    for txin_idx, prev_tx in prev_txs.items():
        ptxin = ptx.inputs()[txin_idx]
        prev_txout = prev_tx.outputs()[ptxin.prevout.out_idx]
        ptxin.witness_utxo = prev_txout
        ptxin.script_descriptor = self.get_script_descriptor_for_address(prev_txout.address)
        if not ptxin.script_descriptor:
            continue  # cannot verify, e.g. watch-only imported address
        txin = tx.inputs()[txin_idx]
        try:
            items = txin.witness_elements() + [x[1] for x in script_GetOp(txin.script_sig or b'')]
            sigs = [x for x in items if x and x[0] == 0x30 and 9 <= len(x) <= 73]
            pubkeys = ptxin.pubkeys
            if len(pubkeys) > 1:  # multisig: sigs are in script order
                script = ptxin.witness_script or ptxin.redeem_script
                pubkeys = [x[1] for x in script_GetOp(script) if x[1] in pubkeys]
        except Exception:
            return False
        sigs_iter = iter(sigs)
        sig = next(sigs_iter, None)
        for pubkey in pubkeys:
            if sig is None:
                break
            try:
                is_valid = ptx.verify_sig_for_txin(
                    txin_index=txin_idx, pubkey_bytes=pubkey, sig=sig, sighash_cache=sighash_cache)
            except Exception:
                is_valid = False
            if is_valid:
                ptxin.sigs_ecdsa[pubkey] = sig
                sig = next(sigs_iter, None)
        try:
            script_sig = Transaction.input_script(ptxin)
            witness = Transaction.serialize_witness(ptxin)
        except MissingSolutionPiece:
            return False
        if script_sig != (txin.script_sig or b'') or witness != (txin.witness or construct_witness([])):
            return False
    return True

Finally, to prevent a malicious server from bypassing mempool signature checks by falsely claiming a spoofed transaction is already mined (tx_height > 0), the patch introduces a staging dictionary self._held_txs. If the server reports a positive block height for an unverified transaction, Electrum holds the transaction in self._held_txs[txid] and defers database insertion until its SPV Merkle proof is cryptographically verified against the block header chain.

> [!NOTE] > Fix Completeness & Residual Surface: The patch specifically validates inputs where self.is_mine(addr) evaluates to True and where the wallet possesses a valid script_descriptor. Unconfirmed incoming transactions from external third parties (is_mine is False on inputs) and watch-only or watchtower wallets (verify_txins=None) are not cryptographically verified in the mempool prior to block confirmation.

Exploitation Methodology

Exploiting CVE-2026-117601 requires the attacker to operate or compromise an Electrum server to which the victim client connects. Because Electrum clients select public servers from peer-advertised lists by default when automatic server selection is enabled, an adversary can deploy rogue Electrum servers onto the network and await incoming client connections.

The attack sequence begins when the connected victim constructs, signs, and broadcasts a legitimate transaction (Tx1) intended for a merchant or external recipient. The victim client transmits the signed raw transaction hex to the malicious Electrum server via the blockchain.transaction.broadcast RPC method. Instead of relaying Tx1 to the Bitcoin peer-to-peer network, the malicious server intercepts and drops Tx1.

Immediately after suppressing Tx1, the server constructs a conflicting transaction (Tx2) that spends the exact same user UTXO(s) referenced in Tx1, but replaces the recipient output scripts with an address controlled by the attacker. The server sets the transaction fee of Tx2 to zero (or 1 sat/vB) so that it appears unable to confirm, populates the input witness or scriptSig with dummy bytes, and sends Tx2 back to the victim client via a blockchain.scripthash.subscribe notification and subsequent blockchain.transaction.get response.

Upon receiving Tx2, the vulnerable Electrum client inserts it into the local database without verifying the input signature. In the victim's GUI, the just-sent transaction appears in the History list as an unconfirmed transaction with an abnormally low fee. To resolve the stuck payment, the user right-clicks the transaction, selects "Bump Fee", adjusts the fee rate slider, and approves the signature prompt. Electrum constructs Tx3 using Tx2's attacker-controlled outputs, signs Tx3 using the user's private keys, and broadcasts Tx3 to the server, which immediately relays it to the Bitcoin network to complete the theft.

Impact Assessment

The primary impact of CVE-2026-117601 is the unauthorized, irreversible theft of cryptocurrency funds from affected wallets. Once the victim signs the Replace-By-Fee replacement transaction (Tx3), the resulting transaction is cryptographically valid according to Bitcoin consensus rules and cannot be revoked once broadcast and mined.

The vulnerability is assigned a CVSS v4.0 base score of 9.3 (Critical) by the assigning CNA (VulnCheck) with the vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N. Under the NVD CVSS v3.1 scoring model, it is rated 7.5 (High) with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H. The divergence in scoring reflects differing interpretations of the attack prerequisites: CVSS v3.1 accounts for the requirement of positioning a malicious Electrum server (AC:H) and relies on the user initiating the RBF workflow (UI:R).

Beyond direct fund loss via RBF poisoning, the lack of signature validation allows a malicious server to corrupt a client's local UTXO state and transaction history. By injecting fabricated unconfirmed transactions spending user coins, a server can cause denial of service to the wallet's coin selection algorithm, making valid UTXOs appear spent and preventing the user from constructing legitimate outgoing transactions until the wallet connects to an honest server and synchronizes.

Remediation & Mitigation

The definitive remediation for CVE-2026-117601 is to upgrade the Electrum client to version 4.8.3 or later. Version 4.8.3 incorporates commit 90fe30822561e515a9d2d6e5a352cc07780999eb, which enforces cryptographic signature validation on all unconfirmed transaction inputs belonging to the wallet and stages purported mined transactions until SPV proof verification completes.

For users who cannot immediately upgrade or who wish to implement defense-in-depth against malicious Electrum server operators, the most effective operational mitigation is to disable automatic server selection and connect exclusively to a self-hosted, trusted Electrum server (such as ElectrumX, Fulcrum, or Electrs) backed by the user's own Bitcoin Core full node. This can be configured via the Electrum GUI under Tools -> Network by unchecking "Select server automatically" or via the command line using the --oneserver and --server arguments.

Additionally, users executing Replace-By-Fee (RBF) or Child-Pays-For-Parent (CPFP) operations should manually verify all destination addresses and output amounts prior to signing. When using hardware wallets (such as Coldcard, Trezor, or Ledger), users must inspect the recipient address displayed on the hardware device's physical screen during the fee-bump signing ceremony to ensure the outputs match the intended recipient rather than relying solely on the host computer's UI.

Official Patches

Electrum (GitHub)Official commit adding signature verification for wallet-owned inputs on unconfirmed transactions.
Electrum (GitHub Security Advisory)GitHub Security Advisory GHSA-6jp4-8v48-cc5v detailing the vulnerability and patched release.

Fix Analysis (1)

Technical Appendix

CVSS Score
9.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.18%
Top 93% most exploited

Affected Systems

Electrum Bitcoin Wallet (spesmilo/electrum)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Electrum Bitcoin Wallet
Electrum Technologies GmbH (spesmilo)
< 4.8.34.8.3
AttributeDetail
Vulnerability IDCVE-2026-117601 / GHSA-6jp4-8v48-cc5v
CWE ClassificationCWE-347: Improper Verification of Cryptographic Signature
CVSS v4.0 / v3.1 Score9.3 (Critical) / 7.5 (High)
EPSS Score0.18% (7.12th Percentile)
Attack VectorNetwork (Malicious Electrum Server / SPV Protocol Manipulation)
Affected VersionsElectrum < 4.8.3
Patched VersionElectrum 4.8.3
Primary ImpactTheft of Bitcoin funds via Replace-By-Fee (RBF) transaction poisoning

MITRE ATT&CK Mapping

T1557Adversary-in-the-Middle
Credential Access
T1565.002Data Manipulation: Transmitted Data Manipulation
Impact
T1036Masquerading
Defense Evasion
T1204.001User Execution: Malicious Link
Execution
CWE-347
Improper Verification of Cryptographic Signature

The product does not verify, or improperly verifies, the cryptographic signature for data.

Vulnerability Timeline

Official fix commit 90fe30822561e515a9d2d6e5a352cc07780999eb merged into spesmilo/electrum by SomberNight.
2026-10-23
CVE-2026-117601 published by CNA VulnCheck and GitHub Security Advisory GHSA-6jp4-8v48-cc5v released.
2026-10-27
CVE-2026-117601 indexed and published on the National Vulnerability Database (NVD).
2026-10-27
Electrum version 4.8.3 deployed with signature verification for wallet-owned mempool inputs.
2026-10-28

References & Sources

  • [1]GitHub Security Advisory GHSA-6jp4-8v48-cc5v
  • [2]Electrum Patch Commit 90fe30822561e515a9d2d6e5a352cc07780999eb
  • [3]VulnCheck Advisory: Electrum before 4.8.3 Missing Signature Verification of Mempool Transactions
  • [4]NVD - CVE-2026-117601
  • [5]CVE.org Record: CVE-2026-117601
  • [6]CVE List V5 JSON Record for CVE-2026-117601

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-116577
5.3

CVE-2026-116577: Algorithmic Complexity Denial of Service in Tornado HTTP Header Parser

Tornado versions prior to 6.6.0 contain an inefficient algorithmic complexity vulnerability in the HTTP header parser. When processing requests with obsolete line folding (obs-fold), the HTTPHeaders.parse_line method repeatedly concatenates immutable Python strings within a list structure. An unauthenticated remote attacker can send an HTTP request containing thousands of short header continuation lines to trigger quadratic O(N^2) CPU consumption on the main IOLoop thread, starving concurrent connections and resulting in a denial of service.

Alon Barad
Alon Barad
2 views•10 min read
•about 2 hours ago•CVE-2026-116578
2.1

CVE-2026-116578: Open Redirect in Tornado RedirectHandler via URL Normalization and Template Substitution

Tornado versions prior to 6.6.0 contain an open redirect vulnerability (CWE-601) in tornado.web.RedirectHandler. When route templates incorporate regular expression capture groups at the start of a path, directly after a fixed host without a trailing slash, or at the beginning of a destination template, unvalidated URL-decoded parameters allow attackers to manipulate the redirect scheme or network location. Because modern browsers normalize URLs according to the WHATWG specification—treating backslashes as forward slashes and stripping control characters—attackers can bypass naive prefix checks and redirect victims to arbitrary external domains.

Alon Barad
Alon Barad
3 views•11 min read
•about 3 hours ago•CVE-2026-115927
5.3

CVE-2026-115927: Event Loop Blocking and Memory Amplification in Tornado Chunked Transfer Encoding Parser

Tornado versions prior to 6.6.0 contain an uncontrolled resource consumption vulnerability (CWE-400) in the HTTP/1.1 chunked transfer encoding parser. When processing incoming chunked payloads that have already buffered in the socket read buffer, Tornado parses chunks in a tight synchronous loop without yielding to the event loop. Furthermore, non-streaming request handlers and SimpleAsyncHTTPClient store each chunk as a discrete Python bytes object inside a list, inducing an approximately 20-fold memory overhead for 1-byte chunks.

Amit Schendel
Amit Schendel
5 views•11 min read
•about 5 hours ago•CVE-2026-118254
8.6

CVE-2026-118254: DOM-based Cross-Site Scripting in Highcharts Grid Pagination Module

CVE-2026-118254 (GHSA-r5wg-q8fc-p6w2) is a high-severity DOM-based Cross-Site Scripting (DOM XSS) vulnerability in the pagination module of Highcharts Grid (@highcharts/grid-lite and @highcharts/grid-pro). The flaw stems from the direct assignment of localization configuration strings (lang.pageInfo and lang.pageSizeLabel) and pagination UI labels to DOM elements via the innerHTML property instead of text-safe DOM APIs such as textContent or innerText. When an application passes attacker-controlled data into the Grid localization options with pagination enabled, arbitrary HTML and JavaScript execute automatically within the hosting document's origin context upon component rendering.

Amit Schendel
Amit Schendel
7 views•10 min read
•about 6 hours ago•CVE-2026-118255
8.4

CVE-2026-118255: Cross-Site Scripting via Unfiltered Credits Href in Highcharts Grid

CVE-2026-118255 is a Cross-Site Scripting (XSS) vulnerability in Highcharts Grid and Highcharts Grid Pro. The flaw occurs because the credits component assigns the configuration-supplied credits.href property directly to an HTML anchor element without verifying the URI scheme against the internal Abstract Syntax Tree (AST) allowlist. An attacker who can influence the grid configuration can supply a javascript: URI, resulting in arbitrary JavaScript execution in the victim's browser session when the credits link is clicked.

Amit Schendel
Amit Schendel
8 views•9 min read
•about 11 hours ago•GHSA-F897-62HF-6GXQ
7.5

GHSA-f897-62hf-6gxq: Unbounded Request Body and JSON-RPC Batch DoS in Model Context Protocol TypeScript SDK

The Model Context Protocol (MCP) TypeScript SDK contains an uncontrolled resource consumption vulnerability in its HTTP server transport implementations and middleware adapters. Affected versions fail to enforce upper bounds on incoming HTTP POST request body sizes and JSON-RPC 2.0 batch array lengths. In addition, middleware wrappers for Express and Hono parse request bodies into memory prior to validating Host and Origin headers. Unauthenticated remote attackers can exploit these flaws to trigger Out-Of-Memory (OOM) process crashes or monopolize the single-threaded Node.js event loop.

Amit Schendel
Amit Schendel
6 views•11 min read