Impact
A rogue program already running on the victim's machine, which has filesystem write access to the Electrum data directory, can place arbitrary plugin code in the plugins/ folder, mark that plugin "enabled" by writing into the config file, and hence get Electrum to execute arbitrary code inside the main python process.
Context
- Electrum has support for external and internal (built-in) plugins.
- To load external plugins (.zip files),
- first, one-time, the user needs to set up a "plugin password" (independent of the wallet passwords)
- the user is instructed to store a public key string derived from the plugin password in a file owned by root (world-readable but not writable)
- then to authorize and enable an external plugin, the user is prompted for their plugin password, checked against the stored pubkey
- if matches, the plugin privkey ecdsa-signs the hash of the plugin zip-file, and the hash is stored in the config file (which is 0600, owned by the user, writeable by the python process).
- on application start, zip-file plugins get loaded and are able to run code if there is a valid signature for them in the config file
- The threat model goal is that a rogue non-root process on a compromised machine should not be able to get code execution inside the main Electrum python process.
Affected version
- the external plugin system was introduced in Electrum 4.6.0, already vulnerable to this issue
- Electrum 4.7.2 contains the fix, all prior versions are affected
The bug
- Prior to the introduction of the external plugin system, plugins had their metadata (e.g. full name, description, list of supported GUIs, declared hardware device support) stored as code in their
__init__.py module.
- This meant plugin code would have to be executed to even show a GUI dialog asking the user if they want to enable a plugin.
- To be able to describe an external plugin in the GUI to the user before letting it run code, this metadata was moved from
__init_.py to a manifest.json, which should be safe to parse.
__init__.py was still kept: it is used by plugins that register CLI commands. CLI commands have a name, arguments, a docstring, etc, which we did not want to duplicate in manifest.json - it can just be parsed out at runtime from .py code.
- So plugins are loaded in two steps:
- step 1
[0]: __init__.py is loaded,
- step 2
[1]: the full plugin is loaded
- The vulnerability is that while step 2 validated whether the zip file hash is signed by the plugin password, step 1 only checked if the plugin is marked as "enabled" in the config file - without checking the corresponding signature.
Relevant code snippets
[0] https://github.com/spesmilo/electrum/blob/2a5b1b22beeedec83e30b2f5c2b22915dc5b6b06/electrum/plugin.py#L590
[1] https://github.com/spesmilo/electrum/blob/2a5b1b22beeedec83e30b2f5c2b22915dc5b6b06/electrum/plugin.py#L611
Patches
Electrum 4.7.2 contains the fix: 032dfcf
(cherry-picked in fd7164d)
Timeline
- 2026-03-26: private disclosure received
- 2026-03-26: fixes implemented, reviewed, merged
- 2026-04-02: a bug bounty of 1000 eur in btc was paid to the reporter for responsible disclosure
- 2026-04-02: version 4.7.2 released with fix included
- 2026-04-28: public disclosure
Credits
We thank Kevil_G for finding and responsibly disclosing this issue to us.
Impact
A rogue program already running on the victim's machine, which has filesystem write access to the Electrum data directory, can place arbitrary plugin code in the plugins/ folder, mark that plugin "enabled" by writing into the config file, and hence get Electrum to execute arbitrary code inside the main python process.
Context
Affected version
The bug
__init__.pymodule.__init_.pyto amanifest.json, which should be safe to parse.__init__.pywas still kept: it is used by plugins that register CLI commands. CLI commands have a name, arguments, a docstring, etc, which we did not want to duplicate in manifest.json - it can just be parsed out at runtime from .py code.[0]:__init__.pyis loaded,[1]: the full plugin is loadedRelevant code snippets
Patches
Electrum 4.7.2 contains the fix: 032dfcf
(cherry-picked in fd7164d)
Timeline
Credits
We thank
Kevil_Gfor finding and responsibly disclosing this issue to us.