diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-12 09:47:46 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-12 16:36:54 +0200 |
| commit | 7c3a1d6fd765ef0421d0f3d85e512e10ea2f6f87 (patch) | |
| tree | 00d05d94cbe1216085ffa94173b6643cd50c8b1e /docs/MESHBAY_DESIGN.md | |
| parent | bf7ff9ec311660318c8562abe03ef4db62475c98 (diff) | |
| download | meshbay-7c3a1d6fd765ef0421d0f3d85e512e10ea2f6f87.tar.gz | |
docs: availability between members is a finding category
The first three reviews asked who can read what, who can impersonate whom,
and what a hostile node can forge. None asked what a legitimate but
misconfigured or careless member costs everyone else — which is the question
a group platform lives on, because every member was invited by someone who
trusted them and none of them is an attacker.
C2 had asked "can a node claim a group its owner is not in?" and the answer
was correctly no. Nobody had asked what happens when a node claims one its
owner *is* in but does not host, which is how a group went dark for all of
its members with its real host online throughout.
§13.5b is the register, AV1 to AV8. The lens, for anything reviewed from
here: a participant supplies input; if anyone other than the sender bears the
cost, there is a ceiling to write, and it goes on every path that writes the
state.
CLAUDE.md gets the working rule and the incident as a lesson, and the stale
path to sync-ui.js corrected — it lives under scripts/, not build/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4YmK41VsEURWFdop4EEeT
Diffstat (limited to 'docs/MESHBAY_DESIGN.md')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index f125825..bda33f1 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -2471,6 +2471,35 @@ Two structural recommendations from that review stand as rules: | **T2** | The hub was the key directory. **Closed** by admission redesign, not by safety numbers: the invite path reads no directory at all (§3.4). Reclassified as **H3** | | **T3** | **The hub serves the SPA. Accepted permanently for browser users.** It is the only remaining way an active hub reads content, it is an artifact-level attack rather than a silent lie, and it does not exist for a native client — whose value is realised by reproducible builds, not by packaging (§2.3, §8.2) | +### 13.5b Availability between members (`AV`) + +**Added 2026-09-12, after the finding that produced it.** The first three +reviews asked who can read what, who can impersonate whom, and what a hostile +node can forge. None asked **what a legitimate but misconfigured or careless +member costs everyone else** — and that is the question a group platform lives +on, because every member was invited by someone who trusted them and none of +them is an attacker. `C2` had asked "can a node claim a group its owner is not +in?" and the answer was correctly no; nobody had asked what happens when a node +claims one its owner *is* in but which it does not host, which is how a group +went dark for all of its members on 2026-09-11 with its real host online +throughout. + +The lens, for anything reviewed from here: **a participant supplies input; who +else bears the cost?** Where the answer is "someone other than the sender", +there must be a ceiling, and it must apply on every path that writes the state +— not only the one where the ceiling was first thought of. + +| Label | The rule it names | +|---|---| +| **AV1** | **An empty claim is a claim on nothing.** A node's group set is `authorized ∩ claimed`, and an absent or empty `group_ids` registers it for no group rather than all of its owner's — on registration and on `update_groups` alike (§7.2) | +| **AV2** | **A client treats the hub's node list as candidates, not a ranking**, and tries the next one on a `not_hosted` refusal (`MESHBAY_NODE_PROTOCOL.md` §6.3) | +| **AV3** | **A node speaks only for the groups it is registered for.** `chat_notify` names a group and is checked against that node's set before a notification is written for anyone, and it is rate-limited per node — the fan-out is one write per member | +| **AV4** | **Nobody names a third party's address.** A swarm source publishes a transport and a port, never a host; where a peer is comes from its node record, stamped with the address its announce arrived from. The number of hashes one account may claim is bounded | +| **AV5** | **An answer is accepted only from the node the offer was sent to.** A `peer_id` is bound to its node, so no connected node can resolve another's pending offer | +| **AV6** | **A relay proves possession of its approved key.** A public key is not a password, and the register call is unauthenticated by design — it is not a user — so the proof is the only thing standing between a stranger and where nodes send relayed traffic | +| **AV7** | **A node bounds how many peers it holds and how long an unproven one lasts.** The hub's cap is per calling account, which is a limit on each member and not on the machine, so without this an operator's exposure grew with the size of their groups | +| **AV8** | **One account cannot make the hub mail another at will.** The invitation email's subject comes from the group row, never from the request, and the endpoint is metered | + ### 13.6 Chat design findings | Label | The rule it names | |