diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-13 11:00:39 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-13 11:00:39 +0200 |
| commit | 9df71bd1e5244743fae8c1b2bda41143f0748d9d (patch) | |
| tree | b3cdf8ca3e87d35bdf54283d6cca34952d0bcf79 /site | |
| parent | ab4657789eaca1d88b54e5d5123a0bc71a95e6ce (diff) | |
| download | meshbay-9df71bd1e5244743fae8c1b2bda41143f0748d9d.tar.gz | |
fix: swarm privacy, revocation persistence, keystore KDF, audit integrity
Phase 11.5 hardening batch — H7, H4, M2, M6, M7, L1, L3, L6.
H7 — private content hashes leaked to the hub. The daemon registered blake3
hashes for every group it hosted, private ones included, giving the hub a
content fingerprint of every private file and letting anyone confirm whether a
known file exists in the network. The leak was dormant only because the routes
were declared on the groups router with a full path and mounted at
/v1/groups/v1/swarm/* — the node's calls 404'd into a swallowed exception.
Fixing the path alone would have activated the leak, so both land together:
registration is gated on group visibility, the routes moved to a real
/v1/swarm router, and the lookup now requires authentication.
H4 — revocation was advisory. Group revocations were signed and broadcast by
the hub and then dropped by the node, whose handler understood only "user" and
"jti", so "suspend a group" enforced nothing. The denylist was also in-memory
only, so a restart silently un-revoked everyone. Now persisted to
data_dir/denylist.json, group targets honoured on both transports, and live
sessions for a revoked group are closed.
M2 — the node keystore, which protects the node's Ed25519 and X25519 private
keys, was still deriving at 64 MB long after the hub's password verifier moved
to 256 MB; the docs recorded the bump as done, true for the hub only. Raising
the constant alone would have made every existing keystore permanently
undecryptable, so envelopes now record the parameters they were written with
and pre-M2 files continue to open under the legacy profile.
M6 — registration inserted its audit row with a NULL user_id and then ran
UPDATE ip_logs SET user_id=<new> WHERE user_id IS NULL, claiming every
unattributed row in the table: failed logins for other usernames, concurrent
registrations. In logs retained a year for legal requests, that attributed
other people's connections to the wrong account.
M7 — X-Forwarded-For was trusted unconditionally at four call sites, so anyone
could forge the IP written to the compliance log and evade per-IP rate limits.
New netutil.client_ip honours the header only from a trusted proxy and takes
the rightmost hop (the one our proxy appended); no direct header reads remain.
L1 dead GEK_REQUEST/GEK_RESPONSE constants removed; L3 peer errors no longer
echo exception text (paths, internal state); L6 email sanity-checked instead of
accepting any string — deliberately not RFC 5322, to avoid a new dependency.
test_daemon_index_change_pushes_to_peers asserted that a PRIVATE group's hashes
are registered with the hub. Split: private asserts not-called (index push to
members still asserted), and a new test proves public groups still register.
That is the fourth pre-existing test found asserting a vulnerability as
intended behaviour, after gek auto-activation, the transport-wide chat_store
and the blind admin challenge.
Tests: 116 node, 132 hub+common. Regression suite now 43.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'site')
0 files changed, 0 insertions, 0 deletions