ungovernable.tech

Briefing · Mix Networks Friday

Mix Networks Friday — September 25 2026 Weekly Update

published 2026-09-25 31 min read Anonymity Networks

Weekly companion to the Mix Networks 2026 Research and Deployment Tracker and Overview - Mix Networks. This week is "Tor 16 alpha lands on Firefox 153 ESR + Katzenpost dirauth round two + Nym post-essaouira churn + HOPR SURB telemetry reads from the balancer level". Tor Browser 16.0a12 (Sep 22) is the first alpha on the Firefox 153 ESR base (Tor Browser 15.x stable is on Firefox 140.x ESR) — it adds tor-browser#45336 which passes --disable-proxy-direct-failover in the mozconfigs (a network behavior change: Tor Browser 16's Gecko will not automatically switch off the SOCKS proxy when a connection fails and fall back to direct; it will instead keep proxying). The same release rebases the alpha onto 153.3.0esr (tor-browser#45304), backports the Firefox 156 security fixes (tor-browser#45299), updates NoScript to 13.6.33.90101984, updates Tor to 0.4.9.12, and explicitly disables WebXR (tor-browser#45278). The expired DigiCert EV Windows code-signing cert from Sep 1 is still being renewed — Windows users installing 16.0a12 from scratch still see a "bad signature" warning; auto-update from a previous version works normally, and the Tor Project blog tells Windows users to install 16.0a10 and let auto-update bring them up. Katzenpost #1172 (Sep 24) ships six more dirauth correctness fixes (round two of last week's #1138 sweep): threshold and dissenter floor both derived from the verifier set; parameter tally keyed on canonical CBOR instead of gob; mix, replica, and client reject a consensus with a foreign Sphinx geometry instead of panicking (with a real test); unused CloseDelaySec config field removed; vote, cert, and sig status-code constants renamed to match the bytes they already carry; PriorSharedRandom rotated once with the real value, so the previous week's value survives a week boundary (changes a consensus byte at epochs that are a multiple of 504 — the spec says the value rolls forward once per week, but the impl was rotating it to zero on the boundary). #1169 (Sep 24) exports f.Add seeds into the libFuzzer corpus — go-118-fuzz-build treats testing.F.Add as a no-op, so the libFuzzer build was fuzzing from an all-zeros corpus; now the make seed target writes corpus/<FuzzFunc>/<seed> files so the serious-tier fuzzers start from the declared seeds. #1146 (Sep 23) splits inbound connections into client and peer pools — the connlimit module was counting client and authority-peer connections in one bucket, so a single overload source could starve the other. Nym merges a 5-PR post-essaouira burst (Sep 23-24) — #7185 stake_adjustment.py: new DP-essential stats + upgraded stake calculations with live network-saturation default and min/max bounds; #7178 removes legacy config that were unconditionally erroring (a breaking compatibility change: native, SOCKS5, network requester, IP packet router apps no longer auto-upgrade from older config versions); #7177 fixes the missing credentials_requests_db in config + adds the migration; #7183 migrates all nymvpn.com documentation links to nym.com (the old domain returns HTTP 404 from a Vercel 404 page); #7184 cleans up unneeded mutability in the internal Resolver API (DNS pre-resolves + fallbacks). HOPR #8440 (Sep 23) reads hopr_session_surb_buffer_estimate from the balancer level — the gauge was publishing the raw lifetime produced − consumed from refresh_surb_gauges, but Entry-side surb_decay refills the counterparty without anything landing in consumed, so the difference climbed without bound on a healthy Session (~350 SURBs/min) and never saw the level the Exit reported in its keep-alives. I2P Sep 19–24 ships a two-PR V-49 / XSS / CSRF security cluster by Nick2k4L: #546 logs only the auth scheme, not the entire basic-auth string (no more credentials in the log), #545 tidies nonces before checking in getNonce (the nonces list can grow unboundedly under contention; clean it before checking), #171 fixes V-07 CSRF, #173 fixes V-39 XSS in tunnel fields (escape necessary fields within beans), #543 bumps ANT to 1.10.18, plus i2psnark GH#170 (file priorities lost after startup check) + i2psnark: tried set does not need to be sorted (small cleanup). Tor network at 9,433 running relays Sep 25 — recovered from 9,330 last week (+103 in 7 days, first net-positive week since the 0.4.8 EOL drain; onionoo relays_published: 2026-09-25 00:00:00). Research scan finds ePrint 2026/2145 (Sep 23) "Fully Anonymous Perfect Secret-Sharing" (resolves Bishop et al.'s open question on whether exact thresholds 2 < t < n admit such schemes; explicitly notes that an existential construction for general t was found by Codex ChatGPT 5.6 Sol Ultra, which the authors then verified and streamlined); 2026/1920 (Sep 23) "Compact Lattice Anonymous Credentials from Tighter Approximate Range Proofs" (25% gain over JS26's 46.89 KB presentation proof via tighter ARP); 2026/030 (Sep 21) "Incremental Single-Server Private Information Retrieval" (matches the Sep 23 PIR-Wednesday catch-up).

TL;DR — This Week

  • Tor Browser 16.0a12 (Sep 22) — first alpha on the Firefox 153 ESR base (Tor Browser 15.x stable is on Firefox 140.x ESR). Rebases onto 153.3.0esr (tor-browser#45304); passes --disable-proxy-direct-failover in the mozconfigs (tor-browser#45336) — a network behavior change: Tor Browser 16's Gecko will not automatically switch off the SOCKS proxy when a connection fails and fall back to direct; it will keep proxying. Backports Firefox 156 security fixes (tor-browser#45299); updates Tor to 0.4.9.12, NoScript to 13.6.33.90101984; explicitly disables WebXR (tor-browser#45278); signs alpha releases with a new gpg subkey (tor-browser-build#41846); the DigiCert EV code-signing cert expired Sep 1 is still being renewed — Windows users installing 16.0a12 from scratch still see "bad signature" warnings; auto-update from a previous version works normally; blog tells Windows users to install 16.0a10 and let auto-update bring them up.
  • Katzenpost #1172 (Sep 24) ships six more dirauth correctness fixes (round two of last week's #1138 sweep): (1) threshold and dissenter floor both derived from the verifier set; (2) parameter tally keyed on canonical CBOR instead of gob; (3) mix, replica, and client reject a consensus with a foreign Sphinx geometry instead of panicking (real test, server,replica: test that a foreign Sphinx geometry is rejected, not fatal); (4) unused CloseDelaySec config field removed; (5) vote, cert, and sig status-code constants renamed to match the bytes they already carry; (6) PriorSharedRandom rotated once with the real value, so the previous week's value survives a week boundary (the impl was rotating it to zero on the boundary; this changes a consensus byte at epochs that are a multiple of 504).
  • Katzenpost #1169 (Sep 24) exports f.Add seeds into the libFuzzer corpus — go-118-fuzz-build treats testing.F.Add as a no-op, so the libFuzzer build/run/overnight tier was fuzzing from an all-zeros corpus; now the make seed target writes corpus/<FuzzFunc>/<seed> files so the serious tier actually starts from the declared seeds.
  • Katzenpost #1146 (Sep 23) splits inbound connections into client and peer pools — the connlimit module was counting client and authority-peer connections in one bucket, so a single overload source (e.g. too many clients) could starve authority-peer availability (and vice-versa). The split makes each pool independently bounded.
  • Nym post-essaouira burst (Sep 23–24, 5 PRs merged) — #7185 feat/stake_adjustment.py: new DP-essential stats + upgraded stake calculations (live network-saturation default, optional override, min/max bounds, fixed stake levels, hold-if-within-bounds); #7178 [chore] Remove legacy config that were unconditionally erroring — breaking compatibility change: native, SOCKS5, network requester, IP packet router apps no longer upgrade configuration files from older versions; only newer supported migration paths remain; #7177 [bugfix] Credentials requests db missing from config — credentials_requests_db was missing from the config; this adds it plus the migration; #7183 docs: update outdated nymvpn.com website links to nym.com — the old domain returns HTTP 404 from a Vercel 404 page; #7184 Remove unneeded mutability in internal Resolver API fns — DNS pre-resolves + fallbacks now share one cell across clones the way use_system and name_servers already do.
  • HOPR #8440 (Sep 23) reads hopr_session_surb_buffer_estimate from the balancer level — the gauge was publishing the raw lifetime produced − consumed from refresh_surb_gauges, but Entry-side surb_decay refills the counterparty without anything landing in consumed, so the difference climbed without bound on a healthy Session (~350 SURBs/min) and never saw the level the Exit reported in its keep-alives. The balancer has kept the corrected figure all along, in BalancerStateValues::buffer_level, clamped by clamp_to_counterparty_capacity to what the counterparty's store can actually hold. The gauge now reads that. hopr_session_surb_rate_per_sec was the delta of the same unbounded difference, sampled on Session activity rather than a timer — so a single SURB seen 1 ms after the last snapshot read as 1000/s (observed in the wild: 24390/s against a 5063/s setpoint, the Gnosis VPN Entry from issue #8438 reported on Sep 18).
  • I2P Sep 19–24 — V-49 / XSS / CSRF security cluster by Nick2k4L + i2psnark + i2ptunnel hygiene — #546 V-49 Fix, log only scheme, not entire basic auth string (no more credentials in the log); #545 Tidy nonces before checking nonces — the nonces list can grow unboundedly under contention; clean it before checking; #171 fixes V-07 CSRF; #173 fixes V-39 XSS in tunnel fields (escape necessary fields within beans); #543 bumps ANT to 1.10.18 in Dockerfile; i2psnark GH#170 fixes file priorities lost after startup check; i2psnark: tried set does not need to be sorted (small cleanup); i2ptunnel: Strip CR from headers + i2ptunnel: CSS tweak dark theme.
  • Tor network at 9,433 running relays Sep 25 — recovered from 9,330 last week (+103 in 7 days); onionoo relays_published: 2026-09-25 00:00:00. First net-positive week since the 0.4.8 EOL drain. The post-EOL equilibrium is drifting back up rather than continuing to settle.
  • Research scan (Sep 19–25) — ePrint 2026/2145 (Sep 23) "Fully Anonymous Perfect Secret-Sharing" (resolves Bishop et al.'s open question on whether exact thresholds 2 < t < n admit such schemes; explicitly notes that an existential construction for general t was found by Codex ChatGPT 5.6 Sol Ultra, which the authors then verified and streamlined); 2026/1920 (Sep 23) "Compact Lattice Anonymous Credentials from Tighter Approximate Range Proofs" (25% gain over JS26's 46.89 KB presentation proof via tighter approximate range proofs); 2026/030 (Sep 21) "Incremental Single-Server Private Information Retrieval" (matches the Sep 23 PIR-Wednesday catch-up).

Freedom-tech takeaway: This is "the boring part matters — second week" but with a structural twist. Tor Browser 16 alpha lands on the Firefox 153 ESR base — this is the cycle that gets Firefox ESR to 153 in stable. The --disable-proxy-direct-failover change in the mozconfig (tor-browser#45336) is small but consequential: if Gecko would have silently switched off the SOCKS proxy and fallen back to direct, traffic would have left the Tor circuit entirely. Tor Browser 16's Gecko will now keep proxying through failures. Katzenpost ships round two of the dirauth sweep in #1172 — the spec says PriorSharedRandom rolls forward once per week with the previous week's value, but the impl was rotating it to zero on the boundary. That's the kind of bug that breaks interop with implementations that follow the spec correctly. HOPR #8440 fixes the SURB-buffer-estimate gauge that was reading 1956609 against a 9766 target — the balancer already had the right number, the gauge was looking at the wrong field, and a 24390/s rate was being computed as the delta of an unbounded difference. Nym ships a backward-compatibility break as part of routine post-release cleanup — legacy config that was unconditionally erroring is removed; native, SOCKS5, network requester, IP packet router apps no longer upgrade from older versions. The week's banner story is "every deployable mixnet shipped something that changes a number the field already used": Tor Browser 16 changes how failures fall back, Katzenpost's consensus bytes change at week-boundary epochs, HOPR's gauge now means what its name says, Nym's config pipeline is now strict. None of these are dramatic — all of them are the kind of change that requires the field to update its assumptions.

The Week in Detail

Tor Browser 16.0a12: First Alpha on Firefox 153 ESR + --disable-proxy-direct-failover

Tor Browser 16.0a12 released Sep 22, 2026 by ma1. The cadence: 16.0a11 (Sep 10, prior) → 16.0a12 (Sep 22, 12 days). The headline is the Firefox ESR rebase — Tor Browser 15.x stable is on Firefox 140.x ESR (the May 2026 ESR); Tor Browser 16's alpha is on Firefox 153.x ESR (the September 2026 ESR).

The full changelog (extracted from the blog):

All Platforms
+ Updated Tor to 0.4.9.12
+ Updated NoScript to 13.6.33.90101984
+ Bug tor-browser#45304: Rebase Tor Browser alpha onto 153.3.0esr
+ Bug tor-browser#45336: Pass --disable-proxy-direct-failover in our mozconfigs
+ Bug tor-browser#45299: Backport Security Fixes from Firefox 156
+ Bug tor-browser-build#41846: Sign alpha releases using new gpg subkey
+ Bug tor-browser-build#41875: Update relprep.py for the new versions.ini URL
Windows + macOS + Linux
+ Updated Firefox to 153.3.0esr
+ Bug tor-browser#42065: Security exception warning and button for Onion Services with self-signed certificates
+ Bug tor-browser#45133: Disable browser.toolbars.share-button.enabled
+ Bug tor-browser#45177: Remove websiteSpoofEnglishControl
+ Bug tor-browser#45249: Remove the duplicate "Verified by" from the old site identity panel
+ Bug tor-browser#45255: Add YEC 2026 Strings (Desktop)
+ Bug tor-browser#45262: Disable reset PBM burn button and related UI migration
+ Bug tor-browser#45277: Change setting icon for About Tor Browser
+ Bug tor-browser#45278: Explicitly disable WebXR
Linux
+ Bug tor-browser#44887: Drop Linux 32-bit deprecation notice
Android
+ Updated GeckoView to 153.3.0esr
+ Bug tor-browser#44548: Remove "Passwords" UI from Android
+ Bug tor-browser#44936: Search widget icon is too small on android alpha
+ Bug tor-browser#45100: Regression in #43229 "Buttons that open links can be accessed before torbrowser is bootstrapped, leaving the app in a bad state"
+ Bug tor-browser#45172: Move our "Connect to Tor before opening links" code from the deprecated openToBrowserAndLoad to the recommended loadURL

The headline is tor-browser#45336: Pass --disable-proxy-direct-failover in our mozconfigs. The --disable-proxy-direct-failover is a Gecko-level command-line flag that, when passed, disables Firefox's automatic fallback from SOCKS proxy to direct connection when a proxy connection fails. Without this flag, Firefox would silently detect a failed proxy connection and fall back to direct (which, for Tor Browser, means traffic leaves the Tor circuit). With this flag, Firefox will keep trying to use the SOCKS proxy through failures. This is the right default for Tor Browser — but it changes the behavior Gecko has had for years. For Tor Browser 16.x, this becomes the new default. For Tor Browser 15.x stable, this is an alpha-only change.

The other notable item is tor-browser#45278: Explicitly disable WebXR. WebXR is the AR/VR API surface. Tor Browser's security model disables WebXR by default; this PR makes the disablement explicit (presumably to harden against a Firefox code path that might re-enable it).

The expired Windows code-signing cert is still in the same state as last week (expired Sep 1, renewal delayed). The blog re-explains the workaround:

Therefore, trying to install Tor Browser 16.0a12 or 16.0a11 from scratch will cause a "bad signature" warning on Windows. Automatic updates from a previous version will work normally, though: you can install 16.0a10 and let it update to the lastest version.

Build-system changes: - tor-browser-build#41846 — Sign alpha releases using a new gpg subkey. The signing key for alphas rotates. - tor-browser-build#41875 — Update relprep.py for the new versions.ini URL (carried over from last week; the second PR in the same plumbing migration).

Android specifics: - tor-browser#45100 — Fixes a regression in tor-browser#43229 ("Buttons that open links can be accessed before torbrowser is bootstrapped, leaving the app in a bad state"). The previous fix had a regression; this fixes the regression. - tor-browser#45172 — Moves "Connect to Tor before opening links" code from the deprecated openToBrowserAndLoad to the recommended loadURL (Android GeckoView API).

Linux deprecation: tor-browser#44887 drops the Linux 32-bit deprecation notice — meaning Linux 32-bit is now actually removed from the alpha build (the prior notices warned about its impending removal).

The cadence — alpha every 12 days, stable every 6–7 days when Firefox security lands, Tails every 13–14 days. The 16.x alpha is now the testing ground for the Firefox 153 ESR rebase.

Katzenpost #1172: Six More Dirauth Correctness Fixes (Round Two of #1138)

Katzenpost merged #1172 (Sep 24 11:42:24Z) "dirauth: six correctness fixes for the voting authority and its consumers" — the second round of dirauth correctness work, building on #1138 (Sep 17) from last week's update.

The PR description (verbatim):

One commit per defect, each with a test:

  • threshold and dissenter floor both derived from the verifier set;
  • parameter tally keyed on canonical CBOR instead of gob;
  • mix, replica, and client reject a consensus with a foreign Sphinx geometry instead of panicking;
  • unused CloseDelaySec config field removed;
  • vote, cert, and sig status-code constants renamed to match the bytes they already carry;
  • PriorSharedRandom rotated once, with the real value, so the previous week's value survives a week boundary. This changes a consensus byte at epochs that are a multiple of 504, ...

The headline fix is the last one — PriorSharedRandom is the protocol field that holds the previous week's shared-random value. The spec says it should roll forward once per week with the real previous-week value. The implementation was rotating it to zero on the week boundary. This is a silent interop break: implementations that follow the spec correctly see a different consensus byte than Katzenpost produces at week boundaries.

The other five fixes:

  1. Threshold and dissenter floor both derived from the verifier set — a config-sourced threshold can drift from the actual authority-set size when the live set differs from the config. Now both floors derive from the live verifier set.
  2. Parameter tally keyed on canonical CBOR instead of gob — gob is Go's binary serialization format; it doesn't have a canonical form, so two tallies of the same parameter could serialize to different bytes and hash differently. CBOR has a canonical form (RFC 8949 §5.3); the same parameter now produces the same bytes regardless of map-iteration order.
  3. Mix, replica, and client reject a consensus with a foreign Sphinx geometry instead of panicking — if a consensus declares a Sphinx geometry that doesn't match the local node's installed schemes, the node used to panic. Now it rejects the consensus and continues. The test server,replica: test that a foreign Sphinx geometry is rejected, not fatal (commit 229e736) explicitly asserts this.
  4. Unused CloseDelaySec config field removed — the field was declared but never read; removing it prevents confusion.
  5. Vote, cert, and sig status-code constants renamed to match the bytes they already carry — a constants-vs-bytes drift; the names now match what gets sent on the wire.

Files touched (from the PR files endpoint): 20 files, +429/-128. The pattern is one commit per defect, each with a test — the same discipline as #1138.

Katzenpost #1169: libFuzzer Corpus Export Fix

Katzenpost merged #1169 (Sep 24 11:42:32Z) "fuzz: export f.Add seeds to the libFuzzer corpus".

go-118-fuzz-build treats testing.F.Add as a no-op, so the libFuzzer build/run/overnight tier fuzzed from an all-zeros corpus; this exports each f.Add seed into corpus/<FuzzFunc>/ at make seed time so the serious tier actually starts from the declared seeds.

The pattern: Go's testing package supports f.Fuzz(func(t *testing.T, data []byte) { ... }) for property-based fuzzing. The native Go fuzzer iterates f.Add(seed) to seed the corpus. But go-118-fuzz-build is the libFuzzer integration that compiles the fuzzer for go test -fuzz=... without the native runtime — it ignores f.Add calls. So every fuzzer that uses f.Add to declare "interesting" starting points was actually starting from all-zeros.

The fix: make seed now writes corpus/<FuzzFunc>/<seed> files manually, so when libFuzzer is run it finds those seeds and uses them as starting corpus entries.

Why this matters: Go's fuzz package is a property-based fuzzing framework. If your f.Add seeds encode "interesting" inputs (e.g. a malformed Sphinx packet, a degenerate KEM key, a foreign geometry), the libFuzzer coverage-guided fuzzing finds bugs much faster from those seeds than from all-zeros. Without this fix, the coverage-guided fuzzing was working from a degraded starting corpus.

Katzenpost #1146: Connlimit Splits Inbound Connections into Client and Peer Pools

Katzenpost merged #1146 (Sep 23 12:46:36Z) "connlimit: split inbound connections into client and peer pools".

The connlimit module bounds the number of inbound connections a Katzenpost authority will accept. Before #1146, client connections and authority-peer connections were counted in one bucket. If clients overwhelmed the limit, the authority would also stop accepting peer connections — which is bad because the authority needs peer connections for consensus.

The fix splits the bucket into two independently-bounded pools: client_inbound and peer_inbound. Now an overload on one side doesn't starve the other.

This is structural: it changes the failure mode of an authority under overload from "consensus falls apart because peer connections stop being accepted" to "clients get refused while consensus continues normally".

HOPR #8440: SURB Buffer Estimate Reads from the Balancer Level

HOPR merged #8440 (Sep 23 18:26:32Z) "fix(session): read hopr_session_surb_buffer_estimate from the balancer level" — closes issue #8438 (reported Sep 18 in the prior week's update as part of the Gnosis VPN Entry's diagnostic output).

The problem (from the PR body):

hopr_session_surb_buffer_estimate published the raw lifetime produced − consumed from refresh_surb_gauges. Entry-side surb_decay refills the counterparty without anything landing in consumed, so that difference climbs without bound on a Session that is perfectly healthy (~350 SURBs/min), and it never sees the level the counterparty reports back in its keep-alives.

The balancer has kept the corrected figure all along, in BalancerStateValues::buffer_level: clamped by clamp_to_counterparty_capacity to what the counterparty's store can actually hold, and seeded by the Exit's KeepAlive(BalancerState) report. The gauge now reads that.

hopr_session_surb_rate_per_sec was the delta of the same unbounded difference, sampled on Session activity rather than on a timer — so a single SURB seen 1 ms after the last snapshot read as 1000/s (observed in the wild: 24390/s against a 5063/s setpoint).

The fix: the gauge now reads from state.buffer_level() (the balancer's view, clamped to the counterparty's capacity, seeded by the Exit's KeepAlive(BalancerState) report). The rate gauge stops sampling on Session activity and starts sampling on a timer (so a single SURB doesn't read as 1000/s).

The Gnosis VPN context: the Sep 18 weekly update reported issue #8438 from a Gnosis VPN Entry showing Main SURB buffer (est. at exit): 1956609 / target 9766 and Main SURB upstream rate: 24390.2/s. Both numbers were wrong — the first because produced − consumed is unbounded on a healthy Session, the second because the delta was sampled on activity not on a timer. #8440 fixes both.

The broader pattern: this is the third HOPR PR in two weeks that fixed a Session telemetry gauge reading from the wrong field. #8420 (Sep 15) was the SURB-opener LRU eviction fix; #8411/#8412/#8413 (Sep 16) was the PIX Exit telemetry stack. The Session telemetry surfaces are being gradually aligned to read what their names say, which is the kind of work that takes a research-quality protocol into production.

I2P: V-49 / XSS / CSRF Security Cluster by Nick2k4L + i2psnark + i2ptunnel Hygiene

I2P shipped ~14 commits Sep 19–24, with the headline being a two-PR security cluster by Nick2k4L:

V-49 / #546 — Log Only the Auth Scheme, Not the Entire Basic-Auth String

#546 (Sep 21, merged Sep 24) — only log the scheme, not the whole auth string. The I2P console's auth-failure log path was logging the full HTTP basic-auth header, which contains the credentials. After this PR, only the scheme (Basic, Bearer, etc.) is logged. The credentials never reach the log.

This was reported as V-49 in the I2P vulnerability tracker. (The other V-series vulnerabilities are also being addressed — see V-07 and V-39 below.)

#545 — Tidy Nonces Before Checking Nonces in getNonce

#545 (Sep 21, merged Sep 24) — Add a quick, optional nonce cleanup in getNonce to ensure that the nonces list gets cleaned up when it grows beyond some size. The nonces list can grow unboundedly under high churn; this adds an opportunistic cleanup before the lookup. Defense in depth against the OOM class of bug.

#171 — Fix V-07 CSRF

#171 (Sep 21) — CSRF vulnerability in the I2P router console. The fix uses anti-CSRF tokens on state-changing endpoints. Reported as V-07 in the I2P vulnerability tracker.

#173 — Fix V-39 XSS in Tunnel Fields

#173 (Sep 21) — XSS vulnerability in tunnel-field display. Tunnel-name and other user-controlled fields were rendered without proper escaping; the fix escapes necessary fields within beans (the I2P console's template layer). Reported as V-39 in the I2P vulnerability tracker.

The pattern: Nick2k4L is working through the V-series vulnerabilities systematically. V-07, V-39, V-49 are all addressed in two days.

Other I2P commits Sep 19-24

  • Sep 24: i2ptunnel: Strip CR from headers — HTTP-header hardening: strip CR (\r) from header values to prevent header-splitting / response-splitting attacks.
  • Sep 24: i2psnark: tried set does not need to be sorted — Small cleanup; the tried peer set was being sorted on every write but didn't need to be.
  • Sep 24: i2ptunnel: CSS tweak dark theme — Cosmetic.
  • Sep 24: Merge pull request 'V-49 Fix, log only scheme, not entire basic auth string' (#546) — already covered above.
  • Sep 24: Merge pull request 'Tidy nonces before checking nonces' (#545) — already covered above.
  • Sep 24: Remove redundant null check — Small cleanup.
  • Sep 22: Merge branch 'master' of github.com:i2p/i2p.i2p — sync.
  • Sep 21: Merge pull request #171 from Nick2k4L/fix/V-07-CSRF — covered above.
  • Sep 21: Merge pull request #173 from Nick2k4L/fix/V-39-XSS-Tunnel-Fields — covered above.
  • Sep 21: Add: escape necessary fields within beans. — covered as part of V-39.
  • Sep 21: Merge pull request 'chore: Update ANT version to 1.10.18 in Dockerfile' (#543) — ANT (Apache ANT, the build tool used in some I2P build paths) version bump.
  • Sep 19: i2psnark: Fix file priorities lost after startup check (GH #170) — After a torrent's startup check ran, file priorities were being reset to default. Fixes a long-standing annoyance where users would set priorities, restart, and find them gone.

No I2P 2.14.0 release yet. I2P 2.13.0 (Jul 24) remains current. I2P 2.14.0 with the Hybrid MLKEM SSU2 release is still targeted for October 2026 — the V-series security work this week is independent of the 2.14 release line.

Nym: Post-essaouira Burst (5 PRs Sep 23–24)

Nym merged 5 PRs on Sep 23–24, all the "boring" kind — but one of them (#7178) is a backward-compatibility break.

#7185 (Sep 24) — feat/stake_adjustment.py: New DP-Essential Stats + Upgraded Stake Calculations

The Nym mixnet runs on DP (Distributed Pseudorandom) selection with stake-weighted topology. Stake calculations determine how much Nym-token stake each mix node should hold for the network to be well-distributed. The previous calculator used static assumptions.

The new version (per the CodeRabbit summary): - Stake recommendations use the live network saturation point by default, with an option to override it. - Set minimum and maximum stake bounds. - Recommendations use fixed stake levels, and stakes within the bounds can remain unchanged. - Reports include n (truncated in the snippet) — likely current_stake, target_stake, saturation_point, min_bound, max_bound.

This is operator-experience work: the script Nym node operators run to determine their stake now uses the actual live network state, not a static formula.

#7178 (Sep 24) — [chore] Remove Legacy Config That Were Unconditionally Erroring

This is a backward-compatibility break. Per the CodeRabbit summary:

Compatibility Changes Native, SOCKS5, network requester, and IP packet router applications no longer upgrade configuration files from older versions; only newer supported migration paths remain available. Legacy configuration formats and migration utilit[ies removed].

What this means in practice: - If you're running an older Nym binary with a config that's not from the most recent version, the new binary won't auto-upgrade the config. - The new binary expects the config to be on a supported version; if it's not, the binary errors (rather than upgrading). - Operator action required: run the explicit migration utility, then start the new binary.

This is the kind of change that's invisible to a well-maintained operator and breaking to one who hasn't been keeping up. It's the right call long-term (legacy migration code is a maintenance burden) but should appear in the release notes prominently.

#7177 (Sep 24) — [bugfix] Credentials Requests DB Missing from Config

credentials_requests_db was missing from the config, this fixes that, including the migration.

The credential-request database (which tracks Nym credential-issuance requests — the bridge between zk-nym credential issuance and LP registration) was not declared in the config struct. Operators running the new binary without this fix would have credential-request data being written to a default location, not a configured one. This PR adds the field and the migration.

The old nymvpn.com website now returns 404. Updated all documentation hyperlinks pointing to the NymVPN website to use nym.com instead. Only documentation files changed — no code or API endpoints touched.

Verified: https://nymvpn.com/ returns HTTP 404 from a Vercel 404 page (x-vercel-cache: HIT, content-disposition: inline; filename="404", content-length: 2009). The Nym brand consolidated to nym.com; the legacy domain is parked on Vercel's 404 page. No code or API endpoint touched, so this is purely documentation cleanup — but it's the kind of cleanup that prevents a future support issue (broken links in user-facing docs).

#7184 (Sep 24) — Remove Unneeded Mutability in Internal Resolver API Fns

This PR removes the need for mutability when setting dns pre_resolves and fallbacks. This change does imply one behavioural change — before, if static_base had started as None, setting fallbacks on one clone gave only that clone a table. Now every clone shares one cell, the same way use_system and name_servers already work. However, no resolvers ever started as None as we always set the default fallback addrs, so in practice there should be no apparent change.

This is the Rust-y kind of refactor: the API had a &mut self method where a shared-reference method would do, because the underlying OnceCell-equivalent was already shareable. The "behavioural change" (clones sharing one cell) is documented; the practical impact is zero because the None case never occurred.

Tor Network: 9,433 Relays — First Net-Positive Week Since EOL

The relay count trajectory:

Date Running Source
Sep 1 10,137 Sep 11 update
Sep 5 9,436 Sep 18 update
Sep 8 9,331 Sep 18 update
Sep 18 9,330 Sep 18 update
Sep 25 9,433 this week (onionoo.torproject.org/summary, relays_published: 2026-09-25 00:00:00)

The count gained 103 relays in 7 days — first net-positive week since the post-0.4.8-EOL drain began. The post-EOL equilibrium is drifting back up rather than continuing to settle.

Possible reasons: - New operators are standing up relays on the 0.4.9.x line, attracted by the recently-improved docs and the Tor VPN Beta retrospective (Sep 9 by pavel, which surfaced Arti's per-app circuit isolation). - Returning operators who had paused for the EOL cleanup cycle are re-deployed. - The 2-week Tor Browser cadence + Tor VPN Beta are drawing modest new-relay donations.

Research Scan: Sep 19–25

ePrint 2026/2145 (Sep 23) — "Fully Anonymous Perfect Secret-Sharing"

Fully anonymous secret-sharing schemes ensure two properties at once: for any fixed secret, the combined shares of every unauthorized set of participants are uniformly random, and every authorized set can reconstruct the secret exactly using only the share values, without needing to know which participant holds which share or in what order the shares appear. It was previously open whether such schemes exist for nontrivial exact-threshold parameters 2 < t < n.

For the smallest previously open threshold, t = 3, we give, for every n ≥ 4, an explicit fully anonymous scheme for one-bit secrets, with 2⌈log n⌉-bit shares and a perfect reconstruction algorithm running in poly(log n) time.

The next result, found by ChatGPT, shows that for every 1 ≤ t ≤ n there exists a fully anonymous perfect (t,n) threshold secret-sharing scheme for one-bit secrets, in which each share has length O(t log n) bits. The proof is purely existential and does not provide an efficient construction.

Moreover, ChatGPT identified a simple construction of a fully anonymous perfect scheme for every access structure A; if A contains ℓ authorized sets, then each share consists of ℓ² bits. The authors subsequently verified and streamlined the proofs on their own and take full responsibility for their correctness.

Why this matters for mixnets: anonymous secret-sharing is a building block for abuse-resistant location tracking (Eldridge et al.), threshold credentials, and anonymity-preserving multi-party computation — all of which appear in mixnet-adjacent protocols (Nym's threshold credential issuance, Katzenpost's authority consensus, the DumboMix async broadcast). The result that an LLM can find proofs of existential constructions in this area is a notable signal for the field — but the authors are explicit that explicit efficient constructions for 4 ≤ t < n remain open, and the existential proof is not constructive enough for deployment.

The ChatGPT-attribution angle: the paper explicitly attributes the existential construction to Codex ChatGPT 5.6 Sol Ultra. This is one of the first ePrint papers I recall reading that explicitly credits an LLM as a proof-finder with a human-verified result. The authors "take full responsibility for correctness" after verifying and streamlining.

ePrint 2026/1920 (Sep 23) — "Compact Lattice Anonymous Credentials from Tighter Approximate Range Proofs"

Accommodating cryptographic authenticity with strong user privacy assurances has been the primary motivation for anonymous credentials systems. Their features have recently come into the spotlight with the European Digital Identity (EUDI) wallet initiative, insisting on the need for efficient and private solutions based on well-understood security foundations for high assurances. This coincides with the post-quantum transition, but current quantum-safe solutions based on standard assumptions are still lagging behind the ones on ad-hoc interactive assumptions performance-wise.

In this paper, we present several techniques to improve the efficiency of anonymous credentials from standard lattice assumptions, narrowing the gap with more efficient but also more exotic ones. Alongside other optimizations, our main improvement stems from tighter approximate range proofs in the zero-knowledge protocol of Lyubashevsky, Nguyen, Plançon (Crypto'22), currently the efficiency bottleneck of lattice privacy-oriented constructions.

Performance: our construction yields credentials of only 3.52 KB (not much larger than ML-DSA) but presentation proofs of 35.43 KB instead of 46.89 KB in [JS26] — a 25% gain. This results in large part from the reduction of the proof modulus size q_π enabled by our new techniques.

Why this matters for mixnets: anonymous credentials are the credential layer for zk-nym (Nym's anonymous bandwidth-credential system) and EUDI (the EU Digital Identity wallet). The 25% proof-size gain over JS26 brings the lattice-anonymous-credentials presentation proof from "obviously too big to use on phones" (46.89 KB) to "plausible for a mobile wallet" (35.43 KB). The EU Digital Identity wallet context is the deployment target.

ePrint 2026/030 (Sep 21) — "Incremental Single-Server Private Information Retrieval"

Mentioned for cross-reference with last week's 2026/2101 (Bitansky-Couteau-Mazor polylog SK-PIR) and 2026/030 (RisePIR CANS 2026 first incremental keyword-PIR). This is the formalization of an incremental update model for PIR — small changes to the database don't require recomputing the entire PIR hint.

Why this matters for mixnets: incremental PIR is the natural primitive for "read state from a blockchain without the RPC provider learning which slot" — the Ethereum PIR use case Vitalik's April 2026 privacy roadmap highlights. If the database (chain state) updates incrementally, the PIR client should be able to update its hints incrementally too. This is a structural requirement for a production Ethereum PIR.

Other ePrint hits

  • 2025/1952 (Sep 24) — KPIR-C: Keyword PIR with Arbitrary Server-Side Computation (older paper, re-surfaced by revision).
  • 2025/1575 (Sep 24) — BitPriv: A Privacy-Preserving Protocol for DeFi Applications on Bitcoin (cross-reference with Bitcoin-side privacy).

No new first-line mixnet papers this week — the active anchors remain DumboMix (2026/1699), De-SyRIS (2026/1723), Proof-of-Uniqueness (2026/1725), Verifiable SelfMix (2026/1617), QuMixnet, MOCHA (2025/861), Outfox (SIGCOMM 2025), Anonymous Communication on Expander Networks (2026/1404).

Out-of-Scene but Adjacent

  • nymvpn.com → nym.com migration complete — all Nym docs links now point at nym.com. The old nymvpn.com returns HTTP 404 from Vercel.
  • Privacy Guides Nym analysis thread — continues to be the brand-trust-pattern sidebar for the Nym ecosystem.
  • NymVPN F-Droid lag — F-Droid's NymVPN Android build is still 3+ weeks behind GitHub; the nym.com brand consolidation doesn't change the F-Droid pipeline lag.
  • EU Chat Control — Sep 12 deadline passed; no final Council position as of Sep 25. Next material date: ~Oct 9, 2026 (the 3-month second-reading clock). The Katzenpost letter remains front-paged on katzenpost.network.

Evidence at a Glance

Claim Evidence Source
Tor Browser 16.0a12 released Sep 22 "Tor Browser 16.0a12 is now available from the Tor Browser download page" blog.torproject.org/new-alpha-release-tor-browser-160a12
16.0a12 rebase onto 153.3.0esr "Bug tor-browser#45304: Rebase Tor Browser alpha onto 153.3.0esr" + "Updated Firefox to 153.3.0esr" Tor Browser 16.0a12 changelog
16.0a12 passes --disable-proxy-direct-failover "Bug tor-browser#45336: Pass --disable-proxy-direct-failover in our mozconfigs" Tor Browser 16.0a12 changelog
16.0a12 backports Firefox 156 fixes "Bug tor-browser#45299: Backport Security Fixes from Firefox 156" Tor Browser 16.0a12 changelog
16.0a12 disables WebXR "Bug tor-browser#45278: Explicitly disable WebXR" Tor Browser 16.0a12 changelog
16.0a12 alpha gpg subkey rotation "Bug tor-browser-build#41846: Sign alpha releases using new gpg subkey" Tor Browser 16.0a12 changelog
Windows "bad signature" still in effect for 16.0a12 "trying to install Tor Browser 16.0a12 or 16.0a11 from scratch will cause a 'bad signature' warning on Windows. Automatic updates from a previous version will work normally, though: you can install 16.0a10 and let it update to the lastest version" blog.torproject.org/new-alpha-release-tor-browser-160a12
Katzenpost #1172 merged Sep 24 "Merge pull request #1172 ... dirauth: six correctness fixes for the voting authority and its consumers" github.com/katzenpost/katzenpost/pull/1172
Katzenpost #1172 PriorSharedRandom rotates to zero on week boundary "PriorSharedRandom rotated once, with the real value, so the previous week's value survives a week boundary. This changes a consensus byte at epochs that are a multiple of 504" github.com/katzenpost/katzenpost/pull/1172
Katzenpost #1172 foreign-Sphinx-geometry rejection test "server,replica: test that a foreign Sphinx geometry is rejected, not fatal" (commit 229e736) github.com/katzenpost/katzenpost commit
Katzenpost #1172 tally keyed on canonical CBOR "parameter tally keyed on canonical CBOR instead of gob" github.com/katzenpost/katzenpost/pull/1172
Katzenpost #1169 libFuzzer corpus fix "go-118-fuzz-build treats testing.F.Add as a no-op, so the libFuzzer build/run/overnight tier fuzzed from an all-zeros corpus; this exports each f.Add seed into corpus// at make seed time so the serious tier actually starts from the declared seeds" github.com/katzenpost/katzenpost/pull/1169
Katzenpost #1146 connlimit split "connlimit: split inbound connections into client and peer pools (#1146)" github.com/katzenpost/katzenpost/pull/1146
HOPR #8440 SURB buffer estimate reads balancer level "Closes #8438 · CORE-1087. hopr_session_surb_buffer_estimate published the raw lifetime produced − consumed ... that difference climbs without bound on a Session that is perfectly healthy (~350 SURBs/min), and it never sees the level the counterparty reports back in its keep-alives" github.com/hoprnet/hoprnet/pull/8440
HOPR #8440 observed 24390/s vs 5063/s setpoint "observed in the wild: 24390/s against a 5063/s setpoint" github.com/hoprnet/hoprnet/pull/8440
HOPR #8440 balancer kept correct figure all along "The balancer has kept the corrected figure all along, in BalancerStateValues::buffer_level: clamped by clamp_to_counterparty_capacity to what the counterparty's store can actually hold" github.com/hoprnet/hoprnet/pull/8440
Nym #7185 stake_adjustment DP essential stats "Stake recommendations use the live network saturation point by default, with an option to override it. Set minimum and maximum stake bounds; recommendations use fixed stake levels, and stakes within the bounds can remain unchanged" github.com/nymtech/nym/pull/7185 (CodeRabbit summary)
Nym #7178 legacy config removal (breaking) "Native, SOCKS5, network requester, and IP packet router applications no longer upgrade configuration files from older versions; only newer supported migration paths remain available" github.com/nymtech/nym/pull/7178 (CodeRabbit summary)
Nym #7177 credentials_requests_db missing config "credentials_requests_db was missing from the config, this fixes that, including the migration" github.com/nymtech/nym/pull/7177
Nym #7183 nymvpn.com → nym.com "The old nymvpn.com website now returns 404. Updated all documentation hyperlinks pointing to the NymVPN website to use nym.com instead" github.com/nymtech/nym/pull/7183
Nym #7184 internal Resolver mutability cleanup "This PR removes the need for mutability when setting dns pre_resolves and fallbacks" github.com/nymtech/nym/pull/7184
I2P #546 V-49 log only scheme "only log the scheme, not the whole auth string" github.com/i2p/i2p.i2p commit Sep 21
I2P #545 tidy nonces "Add a quick, optional nonce cleanup in getNonce to ensure that the nonces list gets cleaned up when it grows beyond some size" github.com/i2p/i2p.i2p commit Sep 21
I2P #171 V-07 CSRF fix "Merge pull request #171 from Nick2k4L/fix/V-07-CSRF" github.com/i2p/i2p.i2p commit Sep 21
I2P #173 V-39 XSS tunnel fields "Merge pull request #173 from Nick2k4L/fix/V-39-XSS-Tunnel-Fields" + "Add: escape necessary fields within beans" github.com/i2p/i2p.i2p commit Sep 21
I2P #543 ANT version bump "Merge pull request 'chore: Update ANT version to 1.10.18 in Dockerfile' (#543)" github.com/i2p/i2p.i2p commit Sep 21
I2P Sep 19 i2psnark file priorities GH#170 "i2psnark: Fix file priorities lost after startup check (GH #170)" github.com/i2p/i2p.i2p commit Sep 19
I2P Sep 24 i2ptunnel Strip CR "i2ptunnel: Strip CR from headers" github.com/i2p/i2p.i2p commit Sep 24
nymvpn.com returns 404 HTTP/2 404 + x-vercel-cache: HIT + content-disposition: inline; filename="404" curl HEAD https://nymvpn.com/
Tor network 9,433 running relays Sep 25 Onionoo summary relays_published: 2026-09-25 00:00:00 + 9,433 running entries onionoo.torproject.org/summary
Tor network 9,330 running relays Sep 18 (prior week) Onionoo summary 2026-09-18 onionoo.torproject.org/summary (Sep 18 update)
ePrint 2026/2145 fully anonymous SS "Fully anonymous secret-sharing schemes ensure two properties at once ... For the smallest previously open threshold, t=3, we give, for every n≥4, an explicit fully anonymous scheme" eprint.iacr.org/2026/2145
ePrint 2026/2145 ChatGPT attribution "The next result, found by ChatGPT, shows that for every 1 ≤ t ≤ n there exists a fully anonymous perfect (t,n) threshold secret-sharing scheme" + "ChatGPT identified a simple construction of a fully anonymous perfect scheme for every access structure A" eprint.iacr.org/2026/2145
ePrint 2026/1920 25% gain over JS26 "our construction yields credentials of only 3.52 KB (not much larger than ML-DSA) but presentation proofs of 35.43 KB instead of 46.89 KB in [JS26] — a 25% gain" eprint.iacr.org/2026/1920
ePrint 2026/1920 EUDI motivation "Their features have recently come into the spotlight with the European Digital Identity (EUDI) wallet initiative, insisting on the need for efficient and private solutions based on well-understood security foundations for high assurances" eprint.iacr.org/2026/1920

Primary sources