diff options
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 | |