Keep hostile operators — state actors, known abuse networks — from attaching a
relay to our federated network. Anyone may still run an isolated relay;
that is the product working as intended and must not change.
What already exists (read this before building anything)
Federation is not open by default, so the door this issue guards is not
currently standing open:
FN_FEDERATION defaults to closed (Config.swift:316). Modes are closed / allowlist / open.
The fleet and the docs both run allowlist — the operator names every
peer, and an unnamed one is refused with peerNotAllowed.
Federation.isFetchableHost already rejects peers named by IP literal, which
is the SSRF-shaped version of this problem.
So a hostile relay cannot join today without an operator explicitly adding it. What is missing is help making that decision, and a guard for open.
Proposed work
1. A peer reputation check at allowlist-admission time (the useful half).
When an operator adds a peer, resolve it and screen the resulting addresses
before the peer goes live — not silently, but as a warning the operator has to
acknowledge. Sources worth combining:
ASN / org lookup — flag hosting providers known for abuse, and government
ranges where those are published
Existing blocklists we already pay attention to (CrowdSec is deployed on the
box; its decisions are a free signal)
Country of registration, cross-checked against the peer's stated identity
2. Screening on open mode, if open is ever recommended. Under open the
peer name arrives in a header from anyone. The existing note in Federation.swift already says DNS resolution and pinning must land before open is recommended to anyone; address screening belongs in the same pass.
3. Log and expose, do not silently drop. A refused peer should be visible to
the operator with the reason. Silent refusal makes a misclassification
indistinguishable from a network fault.
Honest limits — worth stating in the code, not just here
⚠️This is whack-a-mole and should be built as such. IP addresses are cheap,
rotatable, and rentable by anyone; an adversary who wants a relay on the network
will get an address that screens clean. That is a reason to build it as an advisory signal supporting a human allowlist decision, not as the gate.
🔴The gate is and should remain cryptographic: the allowlist plus the
pinned federation key. Those are the things an adversary cannot rent. If IP
screening ever becomes the thing standing between a hostile relay and the
network, the design has regressed.
⚠️False positives land on legitimate self-hosters. Someone running a relay
from a VPS in a flagged range is the common case, not the adversary. There must
be an override, and the override must be easy, or this quietly makes
self-hosting worse — which is the opposite of the point.
⚠️"Government IP ranges" are not reliably enumerable. Published allocations
cover a small fraction; most state activity comes from commercial hosting like
everyone else's. Treat the claim in any data source as low-confidence.
Definition of done
Screening runs at peer-admission time and surfaces a reason to the operator
An operator can override any verdict, in one documented step
Refusals are logged with the reason, never silent
Isolated self-hosted relays are unaffected — covered by a test
allowlist remains the gate; screening is advisory and documented as such
## What this is for
Keep hostile operators — state actors, known abuse networks — from attaching a
relay to **our** federated network. Anyone may still run an **isolated** relay;
that is the product working as intended and must not change.
## What already exists (read this before building anything)
Federation is **not open by default**, so the door this issue guards is not
currently standing open:
- `FN_FEDERATION` defaults to **`closed`** (`Config.swift:316`). Modes are
`closed` / `allowlist` / `open`.
- The fleet and the docs both run **`allowlist`** — the operator names every
peer, and an unnamed one is refused with `peerNotAllowed`.
- `Federation.isFetchableHost` already rejects peers named by IP literal, which
is the SSRF-shaped version of this problem.
So a hostile relay cannot join today without an operator explicitly adding it.
**What is missing is help making that decision, and a guard for `open`.**
## Proposed work
**1. A peer reputation check at allowlist-admission time (the useful half).**
When an operator adds a peer, resolve it and screen the resulting addresses
before the peer goes live — not silently, but as a warning the operator has to
acknowledge. Sources worth combining:
- ASN / org lookup — flag hosting providers known for abuse, and government
ranges where those are published
- Existing blocklists we already pay attention to (CrowdSec is deployed on the
box; its decisions are a free signal)
- Country of registration, cross-checked against the peer's stated identity
**2. Screening on `open` mode, if `open` is ever recommended.** Under `open` the
peer name arrives in a header from anyone. The existing note in
`Federation.swift` already says DNS resolution and pinning must land before
`open` is recommended to anyone; address screening belongs in the same pass.
**3. Log and expose, do not silently drop.** A refused peer should be visible to
the operator with the reason. Silent refusal makes a misclassification
indistinguishable from a network fault.
## Honest limits — worth stating in the code, not just here
⚠️ **This is whack-a-mole and should be built as such.** IP addresses are cheap,
rotatable, and rentable by anyone; an adversary who wants a relay on the network
will get an address that screens clean. That is a reason to build it as an
*advisory signal supporting a human allowlist decision*, not as the gate.
🔴 **The gate is and should remain cryptographic**: the allowlist plus the
pinned federation key. Those are the things an adversary cannot rent. If IP
screening ever becomes the thing standing between a hostile relay and the
network, the design has regressed.
⚠️ **False positives land on legitimate self-hosters.** Someone running a relay
from a VPS in a flagged range is the common case, not the adversary. There must
be an override, and the override must be easy, or this quietly makes
self-hosting worse — which is the opposite of the point.
⚠️ **"Government IP ranges" are not reliably enumerable.** Published allocations
cover a small fraction; most state activity comes from commercial hosting like
everyone else's. Treat the claim in any data source as low-confidence.
## Definition of done
- [ ] Screening runs at peer-admission time and surfaces a reason to the operator
- [ ] An operator can override any verdict, in one documented step
- [ ] Refusals are logged with the reason, never silent
- [ ] Isolated self-hosted relays are unaffected — covered by a test
- [ ] `allowlist` remains the gate; screening is advisory and documented as such
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What this is for
Keep hostile operators — state actors, known abuse networks — from attaching a
relay to our federated network. Anyone may still run an isolated relay;
that is the product working as intended and must not change.
What already exists (read this before building anything)
Federation is not open by default, so the door this issue guards is not
currently standing open:
FN_FEDERATIONdefaults toclosed(Config.swift:316). Modes areclosed/allowlist/open.allowlist— the operator names everypeer, and an unnamed one is refused with
peerNotAllowed.Federation.isFetchableHostalready rejects peers named by IP literal, whichis the SSRF-shaped version of this problem.
So a hostile relay cannot join today without an operator explicitly adding it.
What is missing is help making that decision, and a guard for
open.Proposed work
1. A peer reputation check at allowlist-admission time (the useful half).
When an operator adds a peer, resolve it and screen the resulting addresses
before the peer goes live — not silently, but as a warning the operator has to
acknowledge. Sources worth combining:
ranges where those are published
box; its decisions are a free signal)
2. Screening on
openmode, ifopenis ever recommended. Underopenthepeer name arrives in a header from anyone. The existing note in
Federation.swiftalready says DNS resolution and pinning must land beforeopenis recommended to anyone; address screening belongs in the same pass.3. Log and expose, do not silently drop. A refused peer should be visible to
the operator with the reason. Silent refusal makes a misclassification
indistinguishable from a network fault.
Honest limits — worth stating in the code, not just here
⚠️ This is whack-a-mole and should be built as such. IP addresses are cheap,
rotatable, and rentable by anyone; an adversary who wants a relay on the network
will get an address that screens clean. That is a reason to build it as an
advisory signal supporting a human allowlist decision, not as the gate.
🔴 The gate is and should remain cryptographic: the allowlist plus the
pinned federation key. Those are the things an adversary cannot rent. If IP
screening ever becomes the thing standing between a hostile relay and the
network, the design has regressed.
⚠️ False positives land on legitimate self-hosters. Someone running a relay
from a VPS in a flagged range is the common case, not the adversary. There must
be an override, and the override must be easy, or this quietly makes
self-hosting worse — which is the opposite of the point.
⚠️ "Government IP ranges" are not reliably enumerable. Published allocations
cover a small fraction; most state activity comes from commercial hosting like
everyone else's. Treat the claim in any data source as low-confidence.
Definition of done
allowlistremains the gate; screening is advisory and documented as suchmentioned in merge request !76
mentioned in commit
058a897f52