Skip to content

build: update some dependencies, all over#10727

Merged
ecdsa merged 3 commits into
spesmilo:masterfrom
SomberNight:202607_deps
Jul 2, 2026
Merged

build: update some dependencies, all over#10727
ecdsa merged 3 commits into
spesmilo:masterfrom
SomberNight:202607_deps

Conversation

@SomberNight

@SomberNight SomberNight commented Jul 1, 2026

Copy link
Copy Markdown
Member

I tried to be somewhat conservative.

(But really should do this mid-cycle, not just before a release. Then it would be possible to do major version bumps as well.)


done manual QA, like in the stone age:

  • built appimage OK
    • at runtime, used wizard, created wallet for Trezor1, connected to server, used "show address" on Trezor1
  • built windows OK
    • at runtime, used wizard, created wallet for Trezor1, connected to server, used "show address" on Trezor1
  • built macos OK
    • at runtime, used wizard, created standard wallet, opened wallet, connected to server
  • built android OK
    • at runtime
      • used wizard, created 2fa wallet, connected to server
      • opened wallet with lightning channels

note: 3.12 is in security-only status,
so can't bump win/mac binaries without switching to 3.13
(as we don't compile our own cpython for those)
we should bump those to at least 3.13...
somewhat conservative and paranoid...

generated with patch:
```
user@debian:~/wspace/electrum$ git diff
diff --git a/contrib/requirements/requirements-binaries-mac.txt b/contrib/requirements/requirements-binaries-mac.txt
index ab8bd5f..dfbd55c2b 100644
--- a/contrib/requirements/requirements-binaries-mac.txt
+++ b/contrib/requirements/requirements-binaries-mac.txt
@@ -5,3 +5,11 @@ PyQt6<6.7
 PyQt6-Qt6<6.7,!=6.6.3

 cryptography>=2.6
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+cryptography==46.0.7
+pycparser==2.23
diff --git a/contrib/requirements/requirements-binaries.txt b/contrib/requirements/requirements-binaries.txt
index b410896..5771aef24 100644
--- a/contrib/requirements/requirements-binaries.txt
+++ b/contrib/requirements/requirements-binaries.txt
@@ -3,3 +3,12 @@ PyQt6
 # we need at least cryptography>=2.1 for electrum.crypto,
 # and at least cryptography>=2.6 for dnspython[DNSSEC]
 cryptography>=2.6
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+cryptography==46.0.7
+pycparser==2.23
+PyQt6==6.9.1
diff --git a/contrib/requirements/requirements-build-android.txt b/contrib/requirements/requirements-build-android.txt
index e9d2728..4bf6cc1fc 100644
--- a/contrib/requirements/requirements-build-android.txt
+++ b/contrib/requirements/requirements-build-android.txt
@@ -20,3 +20,10 @@ toml
 # needed for the Qt/QML Android GUI:
 # TODO double-check this
 typing-extensions
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+sh==2.2.2
diff --git a/contrib/requirements/requirements-build-appimage.txt b/contrib/requirements/requirements-build-appimage.txt
index ee8b4aa..d79cd93b6 100644
--- a/contrib/requirements/requirements-build-appimage.txt
+++ b/contrib/requirements/requirements-build-appimage.txt
@@ -7,4 +7,11 @@ wheel
 # The pinned Cython must be installed before hidapi is built;
 # otherwise when installing hidapi, pip just downloads the latest Cython.
 # see spesmilo#5859
-Cython>=0.27
\ No newline at end of file
+Cython>=0.27
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+Cython<3.2
diff --git a/contrib/requirements/requirements-build-base.txt b/contrib/requirements/requirements-build-base.txt
index 5bfea96..6cc7d303c 100644
--- a/contrib/requirements/requirements-build-base.txt
+++ b/contrib/requirements/requirements-build-base.txt
@@ -28,3 +28,12 @@ flit_core>=3.4,<4
 # aio-libs/frozenlist and aio-libs/propcache needs:
 # https://github.com/aio-libs/frozenlist/blob/c28f32d6816ca0fa56a5876e84831c46084bb85d/pyproject.toml#L6
 expandvars
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+setuptools-scm<9
+
+expandvars==1.0.0
+poetry-core==2.1.3
diff --git a/contrib/requirements/requirements-build-mac.txt b/contrib/requirements/requirements-build-mac.txt
index 5504223..583c91170 100644
--- a/contrib/requirements/requirements-build-mac.txt
+++ b/contrib/requirements/requirements-build-mac.txt
@@ -15,3 +15,12 @@ packaging>=22.0
 # otherwise when installing hidapi, pip just downloads the latest Cython.
 # see spesmilo#5859
 Cython>=0.27
+
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+Cython<3.2
+pyinstaller-hooks-contrib==2025.4
diff --git a/contrib/requirements/requirements-build-wine.txt b/contrib/requirements/requirements-build-wine.txt
index 80cccba..647a90acb 100644
--- a/contrib/requirements/requirements-build-wine.txt
+++ b/contrib/requirements/requirements-build-wine.txt
@@ -9,3 +9,10 @@ altgraph
 pywin32-ctypes>=0.2.1
 pyinstaller-hooks-contrib>=2025.2
 packaging>=22.0
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+pyinstaller-hooks-contrib==2025.4
diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt
index 5dfb029..3c4955eb6 100644
--- a/contrib/requirements/requirements-hw.txt
+++ b/contrib/requirements/requirements-hw.txt
@@ -30,3 +30,13 @@ pyserial>=3.5.0,<4.0.0
 # prefer older urllib3 to avoid needing hatchling
 # (pulled in via trezor -> requests -> urllib3)
 urllib3<2
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+cryptography==46.0.7
+pycparser==2.23
+libusb1<3.4
+protobuf==3.20.3
diff --git a/contrib/requirements/requirements.txt b/contrib/requirements/requirements.txt
index e9963c1..da9ab8cde 100644
--- a/contrib/requirements/requirements.txt
+++ b/contrib/requirements/requirements.txt
@@ -18,3 +18,15 @@ attrs>=20.1.0,<23
 # - upper limit to avoid needing hatchling at build-time :/
 #   (however newer versions should work at runtime)
 dnspython>=2.2,<2.5
+
+
+pip==25.1.1
+setuptools==80.9.0
+wheel==0.45.1
+
+aiohappyeyeballs<2.7
+jsonpatch==1.33
+jsonpointer==3.0.0
+propcache==0.3.1
+protobuf==3.20.3
+python-socks==2.8.1
```
@SomberNight SomberNight marked this pull request as ready for review July 1, 2026 20:40
@SomberNight SomberNight added this to the 4.8.0 milestone Jul 1, 2026
@SomberNight

Copy link
Copy Markdown
Member Author

Please someone else skim this and validate that I was not last-minute-blackmailed into pulling in some backdoored crap...

@accumulator

Copy link
Copy Markdown
Member

Looked at the commits of network oriented dependencies python-socks, aiohttp-socks: mostly minor refactorings, and aiohttp: quite a lot of additional validation and fixes (good), one notable change area is the refactoring of decompressors, which AFAICS is raising limit of decompression size to very high, so there might lurk a DDoS vector there.

@f321x

f321x commented Jul 2, 2026

Copy link
Copy Markdown
Member

I looked over the diff and let Claude audit it, 5972fc7 lgtm.
It compared the hashes against PyPI, checked for typosquatting and verified the smaller (less audited) sdist libraries code.

FYI, this is the (partial) output:

Backdoor checks — all passed:

- Every pinned PyPI hash is authentic. I parsed all nine regenerated files (80 unique package==version entries, 556 --hash=sha256: pins covering the complete new state, not just changed lines) and checked each hash against PyPI's official per-release file digests. All 556 match a real artifact published on PyPI for exactly that package and version. Zero unknown hashes, zero nonexistent versions, zero yanked artifacts. Since pip's hash-checking mode makes these pins the trust root, this rules out artifact substitution.
- No dependency injection. No packages were added or removed anywhere (rules out typosquats), no entry lost or mutated hashes at an unchanged version, every entry carries hash pins, and there are no --index-url/--extra-index-url/--find-links/--trusted-host/git-or-direct-URL requirements in any requirements file. The freeze script and build tooling are untouched.
- All three upstream tarball hashes verify against official sources. I downloaded and hashed the artifacts myself: Python-3.11.15.tgz sha512 matches both p4a recipe pins; Python-3.12.13.tar.xz sha256 matches make_appimage.sh; openssl-3.0.21.tar.gz sha512 matches the recipe, and its sha256 additionally matches openssl.org's published .sha256 sidecar.
- No suspiciously fresh releases. Of the ~40 bumped versions, only certifi 2026.6.17 was under two weeks old at commit time (13 days — normal for certifi's date-versioned CA-bundle cadence). Everything else is three weeks to years mature, which strongly limits the compromised-fresh-release attack window.

...

I audited the released artifacts, not just repos (the xz lesson): for each changed package I downloaded the exact old and new sdists whose sha256 Electrum pins (verified against both PyPI and the repo's pins), diffed them in full, compared pure-Python wheels byte-for-byte against sdists, checked PyPI Trusted-Publishing attestations, and for the five packages with no attestation cross-checked the sdist against the public GitHub tag. The wallet-critical packages I read line-by-line myself; four parallel agents covered the bulk ones with instructions to verify, not skim.

The lone-developer question, answered directly. For the five packages that are genuinely one-person uploads with no build provenance — slip10, ckcc-protocol, python-socks, aiohttp-socks, ecdsa — the shipped sdists are byte-identical to their public git tags, and I read every changed line besides. A secretly poisoned tarball is ruled out; a public-repo backdoor would additionally have had to survive my source reading, and nothing suspicious exists in those deltas.

Verdicts (old → new, all CLEAN):

┌────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                  Package                   │                                                                               What the delta actually is                                                                               │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ slip10 1.0.1→1.1.0                         │ Drops base58/ecdsa deps; vendored base58 matches upstream verbatim; new point math uses correct curve constants (checked digit-for-digit) and a genuine SLIP-0010 spec fix             │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ckcc-protocol 1.4.0→1.5.0                  │ Coldcard's public feature release (miniscript, restore, opt-in CLI PushTx); Electrum's plugin paths untouched and already compatible                                                   │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ python-socks 2.7.1→2.8.1                   │ SOCKS5 short-error-reply robustness, exception base class, socket-leak fix — five small hunks total                                                                                    │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ aiohttp-socks 0.10.1→0.11.0                │ Own exception classes + wrapping; cosmetics                                                                                                                                            │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ecdsa 0.19.1→0.19.2                        │ Three defensive DER bounds checks + tests; wheel-only _rwlock.py proven to be a pre-existing, inert, byte-unchanged stale build artifact                                               │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ aiohappyeyeballs 2.6.1→2.6.2               │ Typing modernization + empty-input guard                                                                                                                                               │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ certifi 2025.4.26→2026.6.17                │ 31 CAs removed / 6 added — matches Mozilla root-lifecycle policy; every added CA is a known Mozilla-program CA; GitHub-attested                                                        │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ hidapi 0.14.0.post4→0.15.0                 │ Vendored libhidapi matches upstream 0.15.0 feature set; 18k of 21k diff lines are Cython regeneration (structurally verified, and Electrum re-cythonizes from the audited .pyx);       │
│                                            │ report-I/O paths unchanged in substance                                                                                                                                                │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ idna 3.10→3.18                             │ Unicode 15.1→17 regeneration; a full 1.1M-codepoint behavioral sweep proved zero existing normalizations were redirected (the homograph/backdoor vector) — only new-Unicode additions; │
│                                            │  plus documented DoS caps                                                                                                                                                              │
├────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ charset-normalizer 3.4.2→3.4.7             │ Perf/bugfix release; the one genuinely new piece of install-time-executed code in this whole audit (its in-tree PEP 517 backend shim) was read in full — it only conditionally adds    │
│                                            │ mypy to build deps, nothing else                                                                                                                          │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ cbor2, frozenlist, aiosignal               │ Match changelogs; cbor2's C string-decoder boundaries hand-verified, new max_depth is a CVE fix                                                                                        │
├────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ tomli, pycparser, altgraph, macholib,      │ Build-tool deltas fully read; pycparser's regenerated Ply and 1:1 with visible grammar changes; macholib (the macOS binary rewriter) differs by one blank │
│ pyqt6-sip                                  │  line                                                                                                                                                                                  │
└────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Worth passing upstream (correctness, not security): aiohttp-socks 0.11.0's ProxyConnectionError is no o Electrum call sites like electrum/exchange_rate.py:90 that catch (aiohttp.ClientError, TimeoutError,OSError) now fall through to their generic except Exception when a SOCKS/Tor proxy is unreachable — functional but noisier; catching the aiohttp_socks exceptions explicitly would restore clean handling. Two upstream-quality nits  (cbor2's unclamped read from contract-violating file objects, ecdsa's stale wheel files) are non-issue upstream.

Residual limits, stated plainly: compiled platform wheels (charset-normalizer's mypyc builds, cbor2's C wheels, the PyQt6/Qt6 binary blobs) can't be source-diffed — the hash pins guarantee they're the official PyPI artifacts, but their build honesty rests on the maintainers, unchanged from before this bump. And the large team-maini, cryptography, Cython, requests, multidict, yarl) were deliberately out of scope as neither small nor lone-maintainer — they're attested and heavily watched, but nobody read their full deltas in this review.

@ecdsa ecdsa merged commit 76e82fa into spesmilo:master Jul 2, 2026
11 checks passed
@SomberNight

Copy link
Copy Markdown
Member Author

@accumulator

aiohttp: quite a lot of additional validation and fixes (good), one notable change area is the refactoring of decompressors, which AFAICS is raising limit of decompression size to very high, so there might lurk a DDoS vector there.

hmm. still, aiohttp claims to have fixed ~vulnerabilities in many of their recently released versions so it is probably better for us to just follow them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants