# Bedrohungsmodell

Dieses Dokument benennt URnetworks Angreifer und sagt, was das System gegen
jeden einzelnen tut und was nicht. Es ist geschrieben, um angegriffen zu
werden. Wo eine Eigenschaft an eine Bedingung geknüpft ist, steht die
Bedingung im selben Satz; wo etwas eine Designabsicht ist, die der
ausgelieferte Code noch nicht durchsetzt, ist es als **Designabsicht**
gekennzeichnet und nicht als Eigenschaft. Eine Zusammenfassung für Leser, die
die vollständige Akte nicht lesen werden, steht vor Abschnitt 1.

Der Maßstab ist Tors eigene
[Erklärung der Angriffe, die Onion-Routing nicht abwehrt](https://support.torproject.org/about-tor/security/attacks-on-onion-routing/):
Ein Angreifer, der beide Enden eines Circuits beobachtet, kann sie über das
Timing korrelieren, und Tor sagt das öffentlich. URnetwork liefert keinen
Cover-Traffic und kein Padding aus, hier gilt also dasselbe, und Abschnitt 8
sagt es ohne Abmilderung.

**Stand der unabhängigen Prüfung, einmal genannt und für alles Folgende
gültig.** Es gibt kein unabhängiges Audit des Protokolls, der Connect-Engine
oder des Server-Codes des Operators — der Schicht, auf der die
Privacy-Zusagen liegen. Zwei externe Prüfungen aus 2025 decken andere Flächen
ab: ein unabhängiger externer Penetrationstest der Web-Anwendung und der API
(25. April – 5. Mai 2025, mit Zugangsdaten, manuell, OWASP Top 10 plus eine
Prüfung der ASVS-Kontrollen) und eine MASA-AL2-Prüfung der Android-App durch
die Leviathan Security Group (abgeschlossen am 23. Mai 2025), die bestanden
wurde und von der Leviathan selbst sagt, sie sei „keine ganzheitliche
Sicherheitsbewertung oder umfassender Penetrationstest“. Keine der beiden
untersuchte Logging, Aufbewahrung, den Datenpfad oder das Protokoll. Jede
Behauptung in diesem Dokument ist deshalb eine Behauptung über lesbaren
Quellcode, den jeder prüfen kann und den außerhalb des Projekts noch niemand
als Ganzes geprüft hat.

## Wie die Quellenangaben zu lesen sind

Behauptungen zitieren `path:line` gegen die Arbeitsbäume unter
`/Users/brien/urnetwork/{connect,sdk,server,proxy,extension}`, Stand
2026-08-07. Zeilennummern verschieben sich; die Bezeichner nicht. Wo ein
Befund in einem früheren Code-Verifikationsdurchgang festgestellt wurde,
zitiert er `review/verified/ARCHITECTURE.md` oder
`review/verified/PRIVACY-ENFORCEMENT.md`, die derselben Konvention folgen.

Drei Kennzeichnungen werden bewusst verwendet:

- **Eigenschaft** — der Code setzt sie durch, und ein Angreifer, der die
  anderen Parteien kontrolliert, kann sie trotzdem nicht verletzen.
- **Disziplin** — der Code entscheidet sich, etwas nicht zu tun, wozu er in
  der Lage wäre. Eine Deployment-Änderung oder ein einzeiliger Patch könnte
  das umkehren.
- **Designabsicht** — das Design nennt dies als Ziel; der ausgelieferte Code
  setzt es noch nicht durch.

## Zusammenfassung

Dieser Abschnitt ist für Leser, die die vollständige Akte nicht lesen werden.
Jeder Satz darin ist durch einen nummerierten Abschnitt weiter unten oder
durch die Aussage zur unabhängigen Prüfung oben gedeckt.

**Was das System ist.** URnetwork ist ein Privacy-Netzwerk, in dem Mitglieder
Datenverkehr für andere Mitglieder weiterleiten. Der Pfad ist du → Extender →
Operator → Provider → Internet. Die Vertrauensaufteilung liegt zwischen zwei
Relay-Parteien: dem Operator, der weiß, wer du bist, und dem Provider, der
sieht, wohin dein Datenverkehr geht.

**Die zwei Eigenschaften, mit je eigenem Geltungsbereich.** Auf einem
Relay-Pfad erhält der Provider nie deine echte Quell-IP; keine Einstellung
und kein Provider-Build ändert das (§2). Der Operator kann die versiegelte
Sitzung zwischen Client und Provider nicht lesen, die auf den fünf nativen
Apps (Android, iOS, macOS, Windows und Linux) unter dem Namen
Post-Quanten-Verschlüsselung (Post Quantum Encryption) standardmäßig
eingeschaltet ausgeliefert wird (§2.1). Die Browser-Erweiterung hat keine
versiegelte Sitzung — ihr Client-Gerät läuft im Inneren des Operators, der
als Protokoll-Übersetzungspunkt wirkt, eine Versiegelung kann dort also nicht
existieren (§2.4).

**Die Integritätsmängel — einer behoben, einer offen.** Die Versiegelung fiel
früher in jedem Modus still offen aus (fail open). **Behoben am 2026-08-10:**
Mit eingeschalteter Post-Quanten-Verschlüsselung läuft der Client fail-closed
und weigert sich, Anwendungsdaten im Klartext zu senden oder anzunehmen,
statt darauf herabzustufen (§2.2). Ist der Schalter aus, gilt weiterhin das
alte opportunistische Verhalten, und in keinem der beiden Modi meldet
irgendeine App, welcher der beiden Fälle eingetreten ist. Weiterhin offen:
Kann der Operator einen Provider-Schlüssel austauschen? Heute: ja (§7.4) — die
Vertraulichkeit der Versiegelung hält also gegen einen passiven Operator und
gegen einen Angreifer auf dem Pfad, der die Hülle abstreift, nicht aber gegen
einen Operator, der bereit ist, einen falschen Schlüssel auszustellen. Die
Punkte 8 und 9 von `verify/BEFORELAUNCH.md` verfolgen beide; §2.2 und §7.4
beschreiben den aktuellen Stand.

**Wogegen das System nicht schützt.** Ein Angreifer, der sowohl dein
Zugangsnetz als auch die Provider beobachtet, die deinen Datenverkehr tragen,
kann die beiden Enden über Größe und Timing korrelieren (§8.1). Ein globaler
passiver Beobachter liegt vollständig außerhalb des Geltungsbereichs (§8.3).
URnetwork liefert kein Padding, keinen Cover-Traffic und kein Mixing aus;
Abschnitt 11 ist die vollständige Liste.

**Unabhängige Prüfung.** Es gibt kein unabhängiges Audit des Protokolls, der
Connect-Engine oder des Server-Codes des Operators; zwei externe Prüfungen
aus 2025 decken andere Flächen ab: ein Penetrationstest der Web-Anwendung und
der API und eine MASA-AL2-Prüfung der Android-App durch die Leviathan
Security Group, die bestanden wurde.

**Wo die Details stehen.** Die Abschnitte 1 und 2 definieren die Parteien,
die drei Verbindungsmodi und was jede Partei in jedem Modus sieht. Die
Abschnitte 3 bis 5 nehmen sich jeden Angreifer der Reihe nach vor: einen
feindseligen Provider, einen Netzbeobachter und den Operator. Die Abschnitte
6 und 7 behandeln vom Operator betriebene Provider, Kollusion und den
Austausch von Provider-Schlüsseln. Die Abschnitte 8 bis 12 behandeln
Verkehrskorrelation, Gerätekennungen, rechtliche Anordnungen, die Liste
dessen, wogegen das System nicht schützt, und was dieses Dokument nicht
klären konnte. Abschnitt 13 sagt, wohin Schwachstellen und Korrekturen zu
melden sind.

## 1. Die Parteien

| Partei | Betrieben von | Position |
|---|---|---|
| Client | Dem Nutzer | Die App- oder SDK-Instanz; auf dem Browser- und dem Proxy-Pfad läuft sie stattdessen auf den Servern des Operators (§2.4) |
| Ingress-LB | Dem Operator | nginx; stempelt die beobachtete Client-Adresse in `X-UR-Forwarded-For` (`xops/gitops-unused/gitops-prod/urnetwork/connect/ingress.yaml:9` — das einzige Ingress-Manifest im Baum, und sein Verzeichnis heißt `gitops-unused`, es beschreibt also womöglich nicht die Produktion; §12) |
| Connect-Dienst | Dem Operator | Ein oder zwei Prozesse auf verschiedenen Hosts, verbunden über eine interne Exchange-Verbindung (`server/connect/resident.go:2310-2327`). Nicht „ein Relay-Server“ |
| API / Steuerungsebene | Dem Operator | Auth, Provider-Discovery und -Ranking, Verträge, das Nachschlagen öffentlicher Schlüssel (`server/api/api.go`) |
| Provider | Jedem Mitglied | Empfängt weitergeleitete Pakete und wählt das Ziel über die eigene Verbindung an (`connect/ip.go:3932` `RemoteUserNatProvider` → `LocalUserNat`) |
| Extender | Jedem Freiwilligen | Die erste Etappe des Pfades: ein TLS-Weiterleitungs-Relay auf einer unabhängigen Adresse. Trägt die Sitzung Client↔Plattform, ohne sie zu terminieren, sieht also die verbindende IP und kann nicht entschlüsseln (`connect/net_extender.go:51-55`, `connect/extender/extender.go:57-61`) |
| DoH-Resolver | Cloudflare, Google, Quad9, OpenDNS | Der App-Pfad löst DNS über HTTPS durch den Tunnel zu einem dieser vier auf (`connect/net_http_doh.go:150-155`) |
| Zahlungsdienstleister | Stripe, Apple, Google, Solana/Circle | Halten die echte Identität bezahlter Konten; der Operator speichert die Verknüpfungsschlüssel (`server/db_migrations.go:1712-1719`, `:4640`, `:2350-2356`) |

Der Operator ist **BringYour, Inc.**, eine Delaware-Kapitalgesellschaft mit
einer Postanschrift in San Francisco (`docs/legal/ur.xyz/terms.md:16,25`;
`docs/legal/terms.md:269-271`). Abschnitt 10 behandelt, was das für
Rechtsverfahren bedeutet.

## 2. Die drei Modi und was jede Partei sieht

Diese Tabelle ist maßgeblich und stimmt mit `OVERVIEW.md` überein. Alles
Weitere in diesem Dokument ist der Mechanismus dahinter.

| Modus | Operator sieht | Provider sieht | Standard und Verfügbarkeit |
|---|---|---|---|
| **Relay, versiegelt** | Konto/Quellverbindung, Provider-Zuordnung, Chiffretext sowie Timing/Volumen | Ziel-Datenverkehr, Geräte-/Vertrags-ID, **nicht** deine echte Quell-IP | der native Standard, ab Werk; nur native Apps; siehe §2.2 |
| **Relay, Standard** | Konto/Quellverbindung, Provider-Zuordnung, innere Ziele und Paketbytes | Ziel-Datenverkehr, Geräte-/Vertrags-ID, **nicht** deine echte Quell-IP | Browser- und Proxy-Pfade (§2.4) oder Versiegelung aus; ist sie an, wird ein Provider, zu dem sie sich nicht aufbauen lässt, übersprungen statt hier bedient (§2.2) |
| **Direkt** | weniger Relay-Beteiligung | **deine echte Quell-IP** und Ziel-Datenverkehr | opt-in, durch Ausschalten von Starke Anonymisierung (Strong Anonymization, §2.3) |

Es folgen zwei asymmetrische Aussagen, und sie sind nicht gleich stark:

**Die Blindheit des Providers für deine Identität ist eine Eigenschaft, und
sie ist auf beiden Relay-Pfaden bedingungslos.** Der eingehende
Einstiegspunkt des Providers nimmt IDs entgegen, nie eine Adresse:
`RemoteUserNatProvider.Receive` ist über einen `TransferPath` aus drei
16-Byte-IDs parametrisiert (`connect/ip.go:4298-4303`;
`connect/connect.go:45-49`). Kein Transport-Protobuf trägt eine
Client-Adresse, eine Stadt oder ein Land — ein Grep über
`connect/protocol/*.proto` nach `location|city|country|region` liefert nichts
(`review/verified/ARCHITECTURE.md` §1.3). Es gibt keine Einstellung, die das
auf einem Relay-Pfad abschaltet, und kein Provider-Build kann eine Adresse
erlangen, die ihm nie gesendet wird.

**Die Blindheit des Operators für Inhalte ist ein Standardwert, keine
Einstellung — über einem Mechanismus mit nur noch einem Mangel.** Der
Mechanismus hat einen Namen: **Post-Quanten-Verschlüsselung**, ein Schalter im
Connect-Drawer der Android-, iOS-, macOS-, Windows- und Linux-Apps, der eine
Ende-zu-Ende-Sitzung zwischen deinem Client und dem Provider versiegelt
(§2.1). Bedingt ist nicht mehr, ob der Nutzer den Schalter findet, und seit
2026-08-10 ist auch nicht mehr bedingt, ob die Versiegelung still nicht
zustande kam: Ist der Schalter an, trägt eine Verbindung, die sich nicht
versiegeln lässt, überhaupt keinen Anwendungsverkehr, statt ihn im Klartext zu
tragen (§2.2). Bedingt bleibt, ob der Operator, der die Provider-Schlüssel
ausliefert, gegen die die Versiegelung geprüft wird, sie ehrlich ausliefert
(§7.4). Lies das, bevor du dich auf diese Eigenschaft verlässt; für den Nutzer
ist es nicht sichtbar.

**Standard beim Launch: AN.** Der Product Owner hat am 2026-08-07
entschieden, dass die versiegelte Sitzung eingeschaltet ausgeliefert wird,
die Blindheit des Operators ist also der Standard und nicht eine
Entscheidung, die der Nutzer treffen muss. Dieses Dokument ist gegen diesen
Launch-Zustand geschrieben; zum Zeitpunkt des Schreibens steht der Code
weiterhin standardmäßig auf aus (`verify/BEFORELAUNCH.md` Punkt 7).

Diese Lücke wiegt in eine Richtung schwerer als früher. Weil das
Fail-Closed-Gate an denselben Schalter gebunden ist, **verbreitet das
Einschalten des Standards jetzt eine echte Garantie an jeden Nutzer**, statt
bloß die Reichweite eines stillen Fehlschlags zu vergrößern — das Gegenteil
dessen, wovor dieser Abschnitt warnte, als die Versiegelung noch in jedem
Modus offen ausfallen konnte. Was der Standardwert weiterhin nicht beheben
kann, ist §7.4, denn das ist eine Eigenschaft der Versiegelung selbst: Eine
standardmäßig eingeschaltete Versiegelung, in die sich der Operator als MITM
einklinken kann, schützt nur gegen einen passiven Operator.

Die **Browser-Erweiterung hat überhaupt keine versiegelte Sitzung**
(`extension/src/utils/auth-params.ts:33`, `performance_profile: null`). Das
ist Geltungsbereich, kein Standardwert, und die Launch-Entscheidung ändert
daran nichts.

Überall dort, wo die Versiegelung fehlt — die Browser- und Proxy-Endpunkte
(§2.4) und die nativen Apps mit ausgeschalteter Versiegelung (§2.2) —,
terminiert der Operator das TLS/QUIC des Clients und leitet IP-Pakete im
Klartext weiter (`connect/protocol/ip.proto:9-16`). Er *entscheidet sich*
dafür, nur den Routing-Header zu parsen — `FilteredTransferFrame` enthält
nichts als den Transferpfad (`connect/protocol/transfer.proto:85-87`;
`connect/transfer.go:1500-1509`) —, und das ist **Disziplin**, keine
kryptografische Barriere.

### 2.1 Was die Versiegelung genau ist

Eine TLS-1.3-Sitzung direkt zwischen Client und Provider, als gewöhnliche
Control-Frames durch denselben Operator getragen
(`connect/transfer_encrypt.go:44-51`). Der Schlüsselaustausch ist das hybride
**X25519MLKEM768**, mit konventionellem X25519 als Fallback
(`connect/transfer_encrypt.go:373-381,406`); das AEAD ist AES-256-GCM über
einem 32-Byte-Exportschlüssel (`:285-297`); Identitäten sind Ed25519
(`:892-897`), „Post-Quanten“ bezieht sich also allein auf den
Schlüsselaustausch. Wechselseitiges TLS ist Pflicht, und das Peer-Zertifikat
wird auf der Sequence-Schicht gegen das Commitment des Vertrags geprüft statt
vom TLS-Stack (`:388-406`).

### 2.2 Fail-closed, wenn du es verlangst, fail-open, wenn nicht

**Aktualisiert am 2026-08-10. Dieser Abschnitt sagte früher, die Versiegelung
falle still offen aus und es gebe keine Fail-Closed-Option. Das trifft nicht
mehr zu, und die Änderung ist die bedeutendste Härtung in der Geschichte
dieses Dokuments** — sie hat den Downgrade-Vektor in beide Richtungen
geschlossen. Was folgt, ist das aktuelle Verhalten, aus dem Quellcode gelesen.

Verschlüsselung ist weiterhin eine binäre Eigenschaft von `Cipher() != nil`,
und ein Cipher von nil bedeutet weiterhin, dass der Handshake nicht
abgeschlossen wurde: ein gescheiterter Handshake, ein gescheiterter
Identitätsnachweis oder ein Vertrag, der den öffentlichen Schlüssel des Peers
nie getragen hat, lassen ihn allesamt nil. Ein gescheiterter
Identitätsnachweis ist auf der Sitzungsschicht weiterhin nicht fatal — die
Sitzung bleibt „unauthentifiziert“ (`connect/transfer_encrypt.go:1977`), statt
abgebaut zu werden.

**Was sich geändert hat, ist, was danach passiert.** Es gibt jetzt drei Modi
(`connect/transfer_encrypt.go`, `EncryptionMode`):

| Modus | Verhalten |
|---|---|
| `EncryptionModeOff` | Der Nullwert. Sitzungsschicht inaktiv, alles Klartext. |
| `EncryptionModeOpportunistic` | Versiegelt, sobald eine Sitzung zustande kommt, bis dahin Klartext — oder dauerhaft, falls sie nie zustande kommt. Das historische Verhalten. |
| `EncryptionModeRequired` | **Gibt Anwendungsdaten niemals im Klartext an einen Peer weiter, für den eine Sitzung erwartet wird, und nimmt sie von ihm auch nie im Klartext an.** |

Unter `EncryptionModeRequired` wird die Garantie an vier Stellen durchgesetzt:

- **Eingangs-Gate beim Senden** (`connect/transfer.go:2796`). Ein
  Anwendungspaket wartet innerhalb des Zeitlimits des Aufrufers auf den
  Cipher und wird dann *abgelehnt, ungesendet* — nie herabgestuft — mit einem
  typisierten `ErrEncryptionRequiredNotEstablished`.
- **Absicherung beim Senden** (`connect/transfer.go:4125`). Ein Frame, das den
  Writer ohne Cipher erreicht, wird abgelehnt statt geschrieben; das deckt das
  enge Zeitfenster ab, in dem eine Sitzung zwischen Einreihen und Schreiben
  abgebaut wird.
- **Gate beim Empfangen** (`connect/transfer.go:5844`). Ein *Anwendungs-Frame
  im Klartext* von einem Peer, für den eine Sitzung erwartet wird, wird
  verworfen und auditiert — das ist die Hälfte, auf die es am meisten ankommt,
  denn sie schließt das Downgrade, bei dem ein Angreifer die Hülle abstreift
  und der Empfänger den Klartext sonst annehmen würde. Das Frame wird
  bestätigt (ack) und verworfen, statt unbestätigt zu bleiben, denn ein
  zurückgehaltenes Ack würde eine Lücke in die geordnete Sequenz reißen und
  beide Seiten festfahren.
- **Vorfilter für Kandidaten** (`connect/ip_remote_multi_client.go`,
  `EncryptionCapabilityPrefilter`). Ein Fenster-Kandidat, von dem die
  Out-of-Band-Schlüssel-API der Plattform sagt, er habe nie einen
  Identitätsschlüssel veröffentlicht, wird sofort als gescheitert gewertet,
  denn er kann den Handshake nie abschließen. Er beschleunigt nur ein ohnehin
  sicheres Scheitern; er lässt nie einen Kandidaten zu.

Handshake-Control-Frames, Acks und Control-Plane-Peers sind bewusst
ausgenommen — das Gate deckt die Anwendungs-Nutzlast ab, nicht das Gerüst, das
sie erst in Gang bringt.

**Welchen Modus du bekommst, entscheidet der Schalter
Post-Quanten-Verschlüsselung.** Ist er an, läuft der Consumer-Client in
`EncryptionModeRequired` (`connect/ip_remote_multi_client.go:9186-9197`): Ein
Provider, der keine Sitzung aufbauen kann, trägt überhaupt keinen
Anwendungsverkehr für dich, statt ihn im Klartext zu tragen. Der genannte
Preis ist Verfügbarkeit, bewusst in Kauf genommen. Provider laufen in
`EncryptionModeOpportunistic` (`sdk/device_local_provider.go:98`), damit ein
Provider sowohl versiegelte als auch unversiegelte Consumer bedienen kann; das
ist eine Kompatibilitätsentscheidung auf der Responder-Seite und schwächt die
Garantie des Initiators nicht.

**Was das für den Schalter bedeutet.** Mit eingeschalteter PQE fällt die
Versiegelung nicht mehr offen aus: Sie fällt geschlossen aus, laut, beim
Senden wie beim Empfangen. Mit ausgeschalteter PQE gilt das opportunistische
Verhalten, das frühere Fassungen dieses Abschnitts beschrieben haben, in
vollem Umfang weiter — Datenverkehr kann im Klartext fließen, wenn nie eine
Sitzung zustande kommt, und nichts sagt es dem Nutzer. **Die ehrliche Aussage
ist also an eine Bedingung geknüpft, und der Standardwert ist entscheidend**:
siehe den Hinweis **Standard beim Launch: AN** in §2.

Das Verhalten ist durch Tests abgedeckt, nicht nur durch Kommentare —
`TestRequiredEncryptionFailsClosedAgainstPlaintextPeer`,
`TestRequiredGateNonBlockingSendRefusesPreCipher`,
`TestRequiredGateBoundedBudgetRefusesUnsent`,
`TestRequiredSendRefusalTypedErrorAndEvent` und
`TestRequiredContractFreeWithoutKeySourceFailsClosed`.

Ein veralteter Kommentar, den man beim Audit ignorieren sollte: Der Kopf von
`completeHandshake` bei `connect/transfer_encrypt.go:1650-1654` behauptet
weiterhin uneingeschränkt, „der nachfolgende Datenverkehr fließt im Klartext“.
Das stimmt nur im Modus `Off` und `Opportunistic`; unter `Required` setzen die
Gates oben es außer Kraft. Der Kommentar ist älter als die Korrektur.

**Weiterhin offen: Der Nutzer kann nicht sehen, welchen Modus eine Verbindung
bekommen hat.** Es gibt in keiner App eine Anzeige pro Verbindung, ob
versiegelt oder nicht. Die einzigen Signale sind Geräte-Log-Zeilen —
`peer identity proof verified — cipher is now usable`
(`connect/transfer_encrypt.go:1954`) bei Erfolg, ein `Errorf` bei Fehlschlag
und ein `NotifyRequiredSendBlocked`-Ereignis, wenn das Gate ablehnt. Das SDK
stellt einen Änderungs-Hook bereit, das fehlende Stück ist also UI, nicht
Verkabelung.

### 2.3 Der Direktmodus

**Starke Anonymisierung** auszuschalten setzt `AllowDirect`, dessen eigener
Feldkommentar lautet:
`// setting this to true exposes the real source IP to the provider`
(`sdk/sdk.go:710-711`). Der Flow wird auf einen P2P-Stream gezwungen
(`connect/ip_remote_multi_client_probe.go:1176-1178`), über einen
WebRTC/ICE-Datenkanal (`connect/transport_p2p_webrtc.go:986`), und ICE heißt,
dass beide Endpunkte die Adressen des jeweils anderen erfahren. Der Standard
ist aus — ein Nil-Performance-Profil ergibt false
(`connect/ip_remote_multi_client.go:1861-1863`; `sdk/local_state.go:607-616`).

Zwei erzwungene Fälle: Peers im selben Netzwerk (deine eigenen Geräte)
erlauben direkt immer (`connect/ip_remote_multi_client.go:1822-1825`), und
gehostete Geräte erzwingen aus (`sdk/device_local.go:1516-1533`). Beachte,
dass der Direktmodus den Operator *nur aus dem Datenpfad* entfernt. Verträge,
Provider-Auswahl und Steuernachrichten laufen weiterhin über die Plattform,
der Operator erfährt also weiterhin, welchen Provider du genutzt hast und wie
viele Bytes bewegt wurden.

### 2.4 Der Pfad, den die Tabelle nicht abdeckt: die Browser- und die Proxy-Endpunkte

In der Browser-Erweiterung, der Web-App und an den
HTTPS-/SOCKS5-/WireGuard-Endpunkten **betreibt der Operator den Client.** Die
Erweiterung stellt ein serverseitiges Proxy-Gerät bereit
(`extension/src/utils/auth-params.ts:22-36`, `enable_socks`/`enable_http`),
und der Browser wird auf den Proxy-Endpunkt des Operators gerichtet —
standardmäßig HTTPS CONNECT (`extension/src/bridge/background.ts:220`;
`extension/src/utils/proxy-manager.ts:264`). Die SDK-Instanz, die Verträge
öffnet und das Provider-Fenster hält, läuft in `server/proxy`, nicht auf der
Maschine des Nutzers.

Deshalb kann auf diesen Plattformen keine versiegelte Sitzung existieren, und
zwar aus Gründen der Architektur, nicht wegen noch nicht aufgewendeter
Entwicklungsarbeit. Die versiegelte Sitzung läuft Client↔Provider, und ihre
Zusage hängt daran, dass der Client-Endpunkt auf dem eigenen Gerät des
Nutzers lebt. Ein Browser oder ein einfacher Proxy-Client spricht sein
eigenes Protokoll (HTTPS CONNECT, SOCKS5, WireGuard) und kann die Engine des
Netzwerks nicht ausführen, also betreibt der Operator das Gerät des Clients
aus der Ferne und wirkt als Protokoll-Übersetzungspunkt zwischen beiden. Eine
von diesem entfernten Gerät ausgehandelte Versiegelung begänne im Inneren des
Operators — genau der Partei, die die Versiegelung blind machen soll. Die
Implementierung hat diesen Tausch bewusst in Kauf genommen: Diese Flächen
existieren der Bequemlichkeit halber auf Plattformen und Protokollen, die den
vollen Client nicht beherbergen können, und die Docs dürfen sie nicht als
versiegelt beschreiben.

Die Folgen, klar benannt:

- Die Blindheit des Providers für deine Identität gilt weiterhin — der
  Provider erhält weiterhin nur IDs.
- Die Blindheit des Operators existiert auf diesem Pfad in keiner Form. Der
  Operator terminiert die Proxy-Verbindung, erhält den Zielhost aus CONNECT
  und hält die Schlüssel des Clients.
- Das gehostete Gerät installiert keinen DNS-Upgrade-Mux
  (`server/proxy/proxy_device.go:556`, `SetUpgradeMuxSettings(nil)`), das DoH
  im Tunnel des App-Pfades (§3.2) gilt hier also nicht.

Was auf diesem Pfad an die Stelle der Verschlüsselung tritt, ist
Speicherdisziplin: Der Proxy-Datenpfad loggt auf clientgesteuerten Pfaden
nichts, und ein Regressionstest nagelt das fest —
`proxy/socks5_nolog_test.go`, `TestClientDrivenTrafficNeverLogs`, sichert
null Log-Zeilen über fehlerhafte, übergroße und nicht anwählbare Fälle zu.
Zwei ehrliche Vorbehalte: Das erklärte Motiv des Tests ist
Log-Amplification-DoS und nicht Privatsphäre, und der Panic-Recovery-Handler
loggt sehr wohl eine Client-Adresse (`proxy/socks5_server.go:128-131`). Siehe
`review/verified/PRIVACY-ENFORCEMENT.md` §2.2.

## 3. Angreifer: ein feindseliger Provider

**Im Geltungsbereich und vorausgesetzt.** Bereitstellen kann jeder. Es gibt
für die Teilnahme als Provider keine Attestierung, keinen Stake, keine
Identitätsprüfung und keine Sybil-Abwehr — eine Suche über die Bäume server,
connect und sdk nach `sybil|kyc|attestation` liefert nichts Relevantes. Ein
Provider führt Open-Source-Code auf Hardware aus, die er kontrolliert, geh
also davon aus, dass er einen veränderten Build ausführt.

**Was er sieht.** Alles, was ein Internetanbieter für den Datenverkehr sieht,
den er trägt: Ziel-IP und -Port, Paketgrößen und Timing sowie TLS-SNI, wo der
Client es im Klartext sendet. Er empfängt rohe IP-Pakete und wählt sie selbst
an (`connect/protocol/ip.proto:9-16`; `connect/ip.go` `LocalUserNat`). Er
sieht außerdem die `client_id`, die als `SourceId` des Vertrags mitgeführt
wird (`connect/protocol/transfer.pb.go:1779`;
`server/controller/connect_controller.go:461-463`) — eine Kennung pro
Fensterplatz, die nur der Operator zu einem Konto auflösen kann, und nie die
`device_id`, die auf dem Draht kein Feld hat. Ihre Lebensdauer und die
etlichen Dinge, die sehr wohl über Sitzungen hinweg bestehen bleiben, stehen
in §9.

**Was er tun kann.**

- **HTTP im Klartext: lesen und verändern.** Port 80 wird standardmäßig
  unverändert an den Ausgang durchgereicht — `HttpUpgradeUnencrypted` ist der
  Standardmodus (`connect/ip_mux_upgrade.go:38-47`). Für jeden Datenverkehr,
  der nicht selbst verschlüsselt ist, steht ein Provider in derselben
  Position wie ein feindseliger WLAN-Hotspot. HTTPS schützt
  Anwendungsinhalte vor dem Provider; nichts in URnetwork legt eine zweite
  Schicht über das eigene TLS des Ziels.
- **Datenverkehr selektiv verwerfen, verzögern oder anhalten.** Ein Provider,
  der Datenverkehr quittiert, aber keinen zurückgibt, wird als Blackhole
  markiert und entfernt (`connect/ip_remote_multi_client.go:37-54`),
  Verweigerung wird also erkannt und umfahren — aber die Erkennung ist
  statistisch, und der Datenverkehr, den er vor der Entfernung gesehen hat,
  war trotzdem gesehen.
- **Über die Leistung lügen, um Datenverkehr anzuziehen.** Das Ranking nutzt
  gemessene Latenz und gemessenen Durchsatz
  (`server/model/network_client_location_model.go:2430-2447`), und gemessen
  wird beim Operator, es ist keine Selbstauskunft des Providers, das ist also
  begrenzt — aber es ist ein Eingang ins Ranking, keine Integritätskontrolle.
- **Flows innerhalb der eigenen Sicht korrelieren.** Die Bindung pro Website
  pinnt eine Website auf einen Provider
  (`connect/ip_remote_multi_client.go:1234-1240`), ein einzelner Provider
  sieht also für die Websites, die er hält, einen zusammenhängenden Ausschnitt
  des Surfens eines Clients.

**Was er ohne Hilfe nicht tun kann.** Deine echte IP auf einem Relay-Pfad
erfahren, dein Konto oder deine E-Mail-Adresse erfahren oder eine `client_id`
einer Person zuordnen. Dafür braucht es den Operator (§5).

### 3.1 Was `ip_security` einschränkt und was nicht

Die `ip_security`-Schicht der Connect-Engine läuft am eigenen Ausgang des
Providers und auf dem eigenen Gerät des Nutzers, nie zentral beim Operator —
die Felder `IngressSecurityPolicyGenerator`/`EgressSecurityPolicyGenerator`
des Operators existieren, werden aber nie zugewiesen oder gelesen
(`server/connect/resident.go:263-264`;
`review/verified/PRIVACY-ENFORCEMENT.md` §4.1). Sie blockiert BitTorrent- und
Filesharing-Signaturen, opake nicht standardisierte Protokolle, in
Reputationslisten geführte Ziele und Datenverkehr mit Angriffsmustern, und
sie tut das auf bewusst dünner Grundlage: 5-Tupel plus ein Payload-Präfix,
begrenzt auf 8 Pakete / 512 Bytes.

Die Reputationstabellen werden erzeugt, nicht von Hand gepflegt.
`connect/security` und `connect/blocker` fassen öffentliche
Threat-Intelligence-Feeds — abuse.ch Feodo Tracker (Botnetz-C2), Spamhaus
DROP und DROPv6, Emerging Threats (kompromittierte IPs), Blocklist.de, CINS
Army, TweetFeed, ViriBack, BruteForceBlocker — zu gepackten Bereichstabellen
zusammen (46.789 IPv4-Bereiche im Snapshot vom 2026-08-05; der Header von
`connect/ip_security_cfaa_block.go` führt die Feed-Liste und die
Namensnennung). Die Release-Pipeline erzeugt beide Tabellen neu aus den
Live-Feeds (`build/all/run.sh`, der Schritt `CONNECT_IP_UPDATE`), jedes
Release liefert also einen aktuellen Snapshot aus, und ein aktueller Client
blockiert den zuletzt gelisteten Adressraum. Der Snapshot altert mit dem
installierten Build; die Listen aktualisieren sich pro Release, nicht over
the air.

Die Grenze des Payload-Präfixes steht in
`connect/ip_security_dmca.go:117-119`, wobei der Servername aus dem
Flow-Schlüssel gelöscht wird (`:366,386,424`) und Zähler auf
`(version, protocol, port)` geführt werden, wobei das IP-Feld nie aktiviert
ist (`connect/ip_security.go:554,604-624`).

**Sie ist eine Schutzmaßnahme für ehrliche Provider, keine
Sicherheitsmaßnahme gegen feindselige.** Sie begrenzt, was die Verbindung
eines Providers *nach außen tragen* wird. Gegen das, was ein Provider mit dem
Datenverkehr tut, den er sehr wohl trägt, richtet sie nichts aus, sie läuft
in einem Prozess, der dem Provider gehört, und ein veränderter Build kann sie
abschalten. Lies sie nicht als Schranke für einen feindseligen Provider.

Ein Meldedetail gehört hierher, weil es ein Metadatenkanal ist. Ein Treffer
auf eine BitTorrent-Signatur gibt Incident zurück, was `ReportAbuse` aufruft
(`connect/ip.go:4481-4487`) und einen `PeerAudit`-Control-Frame an den
Operator sendet, der die Geräte-ID des Peers und einen Boolean trägt — kein
Ziel, keine Domain, keine Inhalte (`connect/transfer.go:870-876,6653-6683`).
Der Operator hat heute keinen Handler für diesen Nachrichtentyp, beim Empfang
wird also nichts gespeichert
(`server/controller/connect_controller.go:236-250`; ein Grep über das gesamte
Repo nach `PeerAudit` in `server` liefert null Treffer). Das ist eine
**Disziplin**, die eine einzige `case`-Anweisung von der Änderung entfernt
ist. Verwürfe opak verschlüsselten Datenverkehrs sind still, ohne Meldung
(`connect/ip_security_dmca.go:483-486`).

### 3.2 DNS

Auf dem App- und SDK-Pfad wird einfaches DNS auf UDP/TCP 53 abgefangen und
**durch den Tunnel** über DoH aufgelöst
(`connect/ip_mux_upgrade.go:120-148`, standardmäßig installiert bei
`sdk/device_local.go:1120`), zu Cloudflare, Google, Quad9 oder OpenDNS
(`connect/net_http_doh.go:150-155`). Ein Provider sieht daher eine
HTTPS-Verbindung zu einem öffentlichen Resolver, nicht die Anfrage. Zwei
ehrliche Grenzen:

- **Ein DNS-Leck-Fenster beim Start ist im Quellcode dokumentiert.** Solange
  das DoH im Tunnel noch aufgebaut wird, wird eine Anfrage im Wettlauf gegen
  einen Resolver über den Ausgang des **lokalen Hosts** geschickt, „um den
  Preis eines kurzen DNS-Lecks beim Start“
  (`connect/ip_mux_upgrade.go:120-126,78-92`). Dein lokales Netzwerk und dein
  Internetanbieter können diese Anfragen sehen.
- **Der WireGuard-Endpunkt gibt dem Client einen festen öffentlichen Resolver
  mit**, `DNS = 1.1.1.1` (`server/model/network_client_proxy_model.go:760`),
  und Port 53 wird von der Sicherheitsrichtlinie ungeprüft durchgelassen
  (`connect/ip_security_cfaa.go:113`). Auf diesem Pfad durchqueren
  DNS-Anfragen den Provider als einfaches DNS, und der Provider kann sie
  lesen und beantworten.

Die vier DoH-Resolver sind Dritte, die Anfragen von der Ausgangsadresse eines
Providers eintreffen sehen, ohne Verknüpfung zu deinem Konto. Das ist eine
echte Abhängigkeit, und sie lässt sich nicht auf null konfigurieren:
Irgendjemand muss DNS beantworten.

## 4. Angreifer: ein Netzbeobachter

Vier Positionen, von der schwächsten zur stärksten.

**Dein lokales Netzwerk und dein Internetanbieter.** Sie sehen, dass du dich
über TLS/QUIC mit `connect.bringyour.com` verbindest oder mit einem Extender,
dazu Größen und Zeitpunkte. Ziele im Inneren des Tunnels sehen sie nicht,
außer im oben dokumentierten DNS-Fenster beim Start. Wo die Plattform
blockiert ist, treten Extender als gewöhnliche Dienste auf glaubwürdigen
Ports auf, und Clients rotieren Personas mit zufälliger Fragmentierung
(`connect/net_extender_profiles.go:14-30,50-57`), und für Netze, aus denen
nur DNS herauskommt, gibt es einen DNS-förmigen Transport
(`connect/transport_pt.go:18-45`). Das sind Mechanismen zum **Überwinden
lokaler und regionaler Firewalls**, im Rang unter den direkten Transporten
(`connect/transport.go:541-546`).
Sie sind keine Abwehr gegen Verkehrsanalyse und sollten nie als solche
beschrieben werden.

**Wer einen Extender betreibt.** Betreiben kann ihn jeder, die App akzeptiert
eine von Hand eingegebene IP, und standardmäßig ist keine Signatur nötig
(`connect/extender/extender.go:57-61`). Ein Extender ist der TCP-Peer, sieht
also die IP des sich verbindenden Nutzers, und er kann nicht entschlüsseln,
was er weiterleitet, weil die TLS-Sitzung durch ihn hindurch zur Plattform
läuft, statt auf ihm zu terminieren (`connect/net_extender.go:51-55`). Die
Extender-Etappe setzt damit einen Beobachter deiner Adresse im ersten Hop in
den Pfad, der nicht der Operator ist. Das ist der Tausch, den das Design
eingeht, um dich durch eine Sperre zu bringen, und es lohnt sich, über seine
Größe genau zu sein: Die Extender-Etappe fügt keine Verschlüsselung und keine
Anonymität hinzu — sie erfährt, was dein Internetanbieter ohnehin weiß, und
nicht mehr. Im ausgelieferten Client werden die direkten Transporte zuerst im
Wettlauf probiert, und die Extender-Dialer weiten sich aus, wenn jene
scheitern (`connect/net_http.go:675`); ein Client, der mit eigenen Extendern
konfiguriert ist, nutzt sie als einzige Route
(`connect/net_http.go:357,469`).

**Ein Beobachter eines Endes.** Nur die Client-Seite zu beobachten ergibt
„dieser Nutzer ist mit URnetwork verbunden“ und ein Byte-/Timing-Profil. Nur
den Ausgang eines Providers zu beobachten ergibt Ziele und ein
Byte-/Timing-Profil ohne angehängte Identität.

**Ein Beobachter beider Enden.** Siehe §8. Das ist der Angreifer, den
URnetwork nicht abwehrt.

## 5. Angreifer: der Operator

Der Operator authentifiziert Clients, wählt Provider aus und bewertet sie,
verfasst Verträge, verteilt öffentliche Schlüssel und trägt die Pakete auf
den Relay-Pfaden. Geh für diesen Abschnitt davon aus, dass er feindselig ist
oder gezwungen wird.

**Was er ohne jeden zusätzlichen Aufwand sieht:** dein Konto; deine Adresse
im Moment des Verbindens; eine Stadt/Region/ein Land, aus dieser Adresse per
**lokalem** Datenbank-Lookup abgeleitet — `server/ip.go:201` öffnet eine
mitgelieferte `mmdb/ip-ipinfo.mmdb` von der Festplatte, und `ip.go` macht
keinerlei Netzwerkaufrufe, eine Adresse wird also nie an einen
Geolokalisierungsdienst übergeben — pro Verbindung gespeichert
(`server/model/network_client_location_model.go:1392-1414`); welche Provider
dich bedient haben; Bytezahlen; und auf dem Standardpfad die Zieladressen und
Paketbytes im Inneren des Tunnels — obwohl die normalerweise bereits im HTTPS
des Ziels selbst stecken.

**Was er speichert.** Verbindungs- und Auth-Datensätze halten einen
Einweg-Hash mit geheimem Schlüssel über den umgebenden /29-Block (IPv4) bzw.
/56-Block (IPv6) statt der Adresse (`server/ip.go:46-67`). Eine
Präzisierung, auf die es einem Auditor ankommt: Es ist ein einzelner
prozessweiter **Pepper** aus dem Vault, einmal memoisiert, ohne Salt pro
Zeile und ohne jeden Rotationsmechanismus im Repo (`server/ip.go:40-44`); der
IPv4-Schlüsselraum umfasst 2^29 Blöcke, wer den Pepper hält, kann ihn also
per Brute Force umkehren. Die Geheimhaltung des Peppers ist die ganze
Sicherheitseigenschaft. Das `/verify`-Subsystem nutzt für IPv6 /48, nicht /56
(`server/ip.go:74-85`; `server/model/verify_model.go:111`). Der Quellport
wird im Klartext neben dem Hash gespeichert (`server/db_migrations.go:1934`).
Die Audit-Zeile bei der Kontoerstellung verzeichnet den gepepperten Hash und
den Port, nie das rohe `ip:port` (`server/model/network_model.go:961-975`),
und Audit-Zeilen werden nach 180 Tagen entfernt
(`server/model/audit_model.go:984`, eingeplant bei
`server/taskworker/taskworker.go:57,253`).

**Was gar nicht erst existiert, um gespeichert zu werden.** Kein Ziel, kein
Host, keine URL, kein SNI, kein Port und keine Domain taucht irgendwo im
Transferregister auf — ein Grep der vollständigen Migrationsdatei nach diesen
Begriffen liefert null Treffer (`review/verified/PRIVACY-ENFORCEMENT.md`
§1.2). HTTP-Logging läuft durch eine Allowlist aus genau fünf Headern
(`server/http_log.go:15-29`), festgenagelt per Test. Keine Prometheus-Metrik
trägt eine IP, einen Host, ein Ziel, einen Port oder eine Client-ID; von 39
deklarierten Metriken sind nur drei mit Labels versehen, und jedes Label ist
ein begrenztes Enum (`review/verified/PRIVACY-ENFORCEMENT.md` §2.5).
Log-Uploads aus dem Support-Tab werden nach `io.Discard` abgeleitet
(`server/controller/log_file_controller.go:13-16,76`); nur Metadaten bleiben
bestehen.

### 5.1 Wie lange etwas davon aufbewahrt wird und wohin es geht

Die Aufbewahrung wird von eingeplanten Abräumläufen in `server/taskworker`
durchgesetzt, nicht von einer Richtlinie. Die Fenster unten sind aus den
Konstanten abgelesen, die diese Läufe aufrufen, und sie sind kürzer, als die
Datenschutzerklärung — die überhaupt keine Aufbewahrungsfrist nennt — einen
Leser erwarten ließe.

| Daten | Aufbewahrungsdauer | Durchgesetzt bei |
|---|---|---|
| Verbindungszeilen und die pro Verbindung daran hängenden Stadt/Region/Land, Latenz und Geschwindigkeit | **8 Stunden** | `taskworker/work/network_client_work.go:84`; das Löschen kaskadiert im selben Statement auf `network_client_location` (`model/network_client_model.go:2295-2320`) |
| Ein Top-Level-Client untätig (kein Auth, kein Connect) → als inaktiv markiert | **30 Tage** | `TopLevelClientIdleExpiration` (`model/network_client_model.go:2289`) |
| Ein inaktiver Client → harte Löschung, mit Kaskaden | **+30 Tage** | `NetworkClientReapAfterDeactivate` (`:2269`) |
| Ein ungenutztes Gerät also, Ende zu Ende | **~60 Tage** | die beiden verkettet |
| Abgeschlossene Verträge | **7 Tage** | `taskworker/work/subscription_work.go:161` |
| Audit-Zeilen | **180 Tage** | `model/audit_model.go:984` |

Zwei Hinweise, die ein Auditor haben sollte. Das Untätigkeitsfenster wurde
**am 2026-07-18 von 90 Tagen auf 30 verschärft**; die Konstante trägt ihre
eigene Begründung, und ein veralteter Kommentar bei
`taskworker/work/network_client_work.go:83` sagt noch 90 — das ist die
wahrscheinlichste Quelle dieser Zahl, falls sie dir anderswo begegnet. Und
`RemoveLocationLookupResults` ist in jedem Zyklus eingeplant, aber ein
**No-op** — sein Rumpf und sein Model-Aufruf sind beide auskommentiert, und
eine solche Tabelle existiert nicht. Es ist ein funktionsloses Überbleibsel,
keine Daten, die das Abräumen übersieht; der Standort pro Verbindung wird mit
der Verbindungszeile oben gelöscht.

**Die Geolokalisierung verlässt die Maschine nie.** Der
Stadt/Region/Land-Lookup liest eine mitgelieferte `mmdb/ip-ipinfo.mmdb` von
der lokalen Festplatte (`server/ip.go:201`), und `ip.go` enthält keinen
HTTP-Client und macht keine Netzwerkaufrufe. Keine Adresse wird an einen
Geolokalisierungsdienst geschickt, und keine persönlichen Informationen
werden an irgendeinen Dritten weitergegeben. Die einzigen Dritten in der
Parteien-Tabelle dieses Dokuments halten Daten, die der Nutzer ihnen selbst
aushändigt, indem er diesen Weg wählt: die DoH-Resolver, die von den eigenen
DNS-Anfragen eines Nutzers durch den Tunnel erreicht werden, und die
Zahlungsdienstleister, bei denen sich ein Nutzer registriert, um abgerechnet
zu werden.

**Bekannte Lücken in der Haltung „wir loggen deine Adresse nicht“, unabhängig
von der Verbosität.** `server/http.go:415,455` konstruieren `http.Server`
ohne `ErrorLog`, die Go-Standardbibliothek schreibt also bei jeder
halboffenen Verbindung `http: TLS handshake error from <client IP>` auf das
stderr der Produktion — genau das Loch, das `proxy/http.go:176,250` mit
`ErrorLog: discardLog` schließt. Vom Client geliefertes SNI wird auf ERROR
geloggt (`server/tls.go:98,195`), eine rohe Aufruferadresse bei
`server/proxy/proxy_device.go:274` und die WireGuard-Peer-Identität bei
`server/proxy/server.go:699`. Bis das behoben ist, ist „wir loggen deine IP
nie“ keine Aussage, die URnetwork treffen kann, und dieses Dokument trifft
sie nicht. Vollständige Aufstellung:
`review/verified/PRIVACY-ENFORCEMENT.md` §2.4.

**Was der Operator kontrolliert und leicht zu übersehen ist.** Die
Provider-Discovery liegt vollständig auf der Seite des Operators:
`FindProviders2` ist der einzige aktive Endpunkt (`server/api/api.go:67`),
die Plattform bewertet und sortiert die Kandidaten
(`server/model/network_client_location_model.go:2250-2254,2430-2447`), und
der Client nimmt die sortierte Auswahl, die er bekommt. Die einzige Steuerung
auf Verbraucherseite ist eine Sperrliste für Standorte
(`server/api/api.go:73-75`). Ein Client hat keine Möglichkeit zu prüfen, ob
die ihm angebotenen Provider voneinander oder vom Operator unabhängig sind.

## 6. Vom Operator betriebene Provider und Kollusion zwischen Operator und Provider

### 6.1 Kann der Operator Provider betreiben?

**Ja, und nichts im System kennzeichnet oder verhindert das.** Bereitstellen
steht jedem offen, ohne Attestierung und ohne Stake, und im Code gibt es
nirgends ein Konzept von Erstanbieter-, offiziellen oder dem Operator
gehörenden Providern — Suchen über `server`, `connect` und `sdk` nach einer
solchen Vorstellung liefern nichts. Ein vom Operator betriebener Provider
wäre von dem eines Mitglieds nicht zu unterscheiden.

Zusammen mit der Feststellung aus §5, dass der Operator die Provider-Auswahl
sortiert und zurückgibt, heißt das: Der Operator kann im Prinzip eigene
Provider in das Fenster eines Nutzers setzen. Es gibt keine clientseitige
Vielfaltsprüfung, keine Attestierung der Unabhängigkeit und keine
veröffentlichte Vermessung der Flotte durch eine außenstehende Partei. Die
vorhandenen Gegengewichte sind echt, aber nur teilweise wirksam: Das Fenster
hält mehrere Provider zugleich — ein Qualitätsfenster aus 2–6 (harte
Obergrenze 12) und ein Geschwindigkeitsfenster aus 1–2 (harte Obergrenze 4),
beide aktiv im Standardprofil (`connect/ip_remote_multi_client.go:138-158`) —,
und Provider werden bei ungesunden Statistiken, erkanntem Blackhole,
ausbleibendem Ping und der Lebensdauerrotation pro Kanal entfernt
(`:37-54`, `:610-616`). Das begrenzt, wie viel ein einzelner Provider sieht.
Es begrenzt keine Provider-Auswahl, die von einer einzigen Partei getroffen
wird.

### 6.2 Was Operator und Provider gemeinsam rekonstruieren, je Modus

Geh davon aus, dass der Operator und einer oder mehrere Provider in deinem
Fenster teilen, was sie jeweils halten.

| | Relay, Standard | Relay, versiegelt | Direkt |
|---|---|---|---|
| Deine Identität (Konto, E-Mail/Wallet/Zahlung) | Operator | Operator | Operator |
| Deine echte IP zum Verbindungszeitpunkt | Operator | Operator | Operator **und** der Provider direkt |
| Ziele, die du besucht hast | Operator (innere Pakete) **und** Provider | **nur der Provider** | Provider |
| Verknüpfung zwischen beidem | trivial — eine Partei hält bereits beides | der Vertrag: `audit_contract_event` paart Client- und Provider-Identität je Vertrag (`server/db_migrations.go:234-251`) | trivial |
| Ergebnis | vollständige Zuordnung des Surfens für alles, was die kolludierenden Provider getragen haben | vollständige Zuordnung des Surfens für alles, was die kolludierenden Provider getragen haben | vollständige Zuordnung des Surfens, und der Provider kennt deine Adresse ohne fremde Hilfe |

**Der ehrliche Schluss: Die versiegelte Sitzung schützt nicht gegen Kollusion
zwischen Operator und Provider.** Sie nimmt dem Operator die *eigenständige*
Fähigkeit, deinen Datenverkehr zu lesen; sie hindert einen Provider, der
deine Ziele ohnehin sieht, nicht daran, sie einem Operator zu geben, der
ohnehin weiß, wer du bist. Der Vertragsdatensatz, der beides verbindet, ist
kein Leck — er ist die Abrechnung, von der das Netzwerk lebt.

Was die Versiegelung gegen diesen Angreifer sehr wohl erkauft, ist eine
Begrenzung des Geltungsbereichs: Ist sie an, enthält die eigene Sicht des
Operators keine Ziele, Kollusion erfordert also die Mitwirkung genau der
Provider, die genau diesen Datenverkehr getragen haben, und zwar zu der Zeit,
als er getragen wurde, statt einer Abfrage gegen Datensätze, die der Operator
allein hält. Das ist ein bedeutsamer Unterschied im Aufwand und darin, was
eine erzwungene Herausgabe rückwirkend erreichen kann (§10). Es ist keine
Immunität, und keine Anordnung dreier Parteien, in der eine die anderen
auswählt, gewährt Immunität.

**Die strukturelle Antwort des Designs, die nicht ausgerollt ist.** Das
Wire-Protokoll und der Client unterstützen das Verketten weiterer
Provider-Zwischenstationen — `MaxMultihopLength = 8`
(`connect/connect.go:13,214-233`), `IntermediaryIds` an `CreateContract`
(`connect/protocol/transfer.pb.go:1516`), Annahme im Client bei
`connect/ip_remote_multi_client_api.go:296-312`, Server-Verkabelung bei
`server/controller/connect_controller.go:560`. Der aktive
Discovery-Endpunkt füllt das Feld nie — `FindProvidersProvider` wird an genau
zwei Stellen konstruiert, und keine davon setzt es
(`server/model/network_client_location_model.go:3186-3190,3296-3303`) —, das
ausgelieferte Netzwerk vergibt also Ketten der Länge eins.
Provider-Verkettung ist eine Fähigkeit des Protokolls, keine Eigenschaft des
Deployments, und die Zahl 8 als Hop-Zahl zu zitieren wäre irreführend.

## 7. Provider-Identitätsschlüssel und ob der Operator einen austauschen kann

Das ist der Abschnitt, den anzugreifen sich am meisten lohnt, denn die
Antwort ist unbequem, und der Quellcode sagt das selbst.

### 7.1 Ausgabe und Bindung

Jeder `connect.Client` — ein Provider-Client und jeder der Fenster-Clients
des Nutzers — hält ein Ed25519-Schlüsselpaar, das im Prozess von
`ClientKeyManager` erzeugt wird (`connect/transfer_key.go:76-100`, der
einzige Aufruf von `ed25519.GenerateKey` in den drei Bäumen). Es ist
langlebig, wo ein Seed persistiert und wieder geladen wird, was der
Provider-Client tut, und pro Prozess frisch, wo keiner persistiert wird, was
die Fenster-Clients tun; §9 behandelt den Unterschied und warum er zählt. Die
private Hälfte verlässt den Prozess nie; ein Seed falscher Größe ist ein
harter Konstruktionsfehler und keine stille neue Identität (`:84-94`). Die
öffentliche Hälfte wird der Plattform in einer `ClientKey`-Control-Nachricht
bekannt gegeben (`connect/protocol/transfer.proto:501-513`) und serverseitig
in Redis unter `ckey_<clientId>` gespeichert, **ohne Ablauf** — Redis ist die
Quelle der Wahrheit, eine SQL-Tabelle gibt es nicht
(`server/model/network_client_key_model.go:14-59`).

Die Bindung ist damit `client_id → public key`, und der Operator
gibt die `client_id` aus und hält die Zuordnung. Es gibt keinen externen
Anker: IDs werden nicht aus Schlüsseln abgeleitet, und es gibt weder ein
Transparency Log noch eine DHT. Beide Alternativen sind im Design als erwogen
und zurückgestellt vermerkt (`connect/DESIGNNOTES.md` §3.7,
„Deferred alternatives“).

### 7.2 Rotation und Widerruf

Erneutes Veröffentlichen überschreibt — der eigene Kommentar von
`SetClientKey` lautet „nach `client_id` geschlüsselt (Rotation
überschreibt)“ (`server/controller/connect_controller.go:810-813`). Der
Eintrag wird gelöscht, wenn die Client-ID abgeräumt wird
(`network_client_key_model.go:61-71`, aufgerufen aus
`RemoveDisconnectedNetworkClients`). Es gibt **keine planmäßige Rotation,
keinen Ablauf und keine Widerrufsliste.** Ein Provider-Client persistiert sein
Schlüsselmaterial und lädt es wieder, seine Identität ist über Neustarts
hinweg also stabil (`sdk/device_local.go:2874-2889,2926-2935`;
`sdk/local_state.go:418-461`) — und unter Android bewusst auch über eine
automatische Abmelde-Bereinigung hinweg stabil (§9.2). Ein Client ohne
persistierten Seed erzeugt bei jedem Prozessstart eine neue Identität, und
genau das tun die Fenster-Clients des Nutzers. Schlüsselwechsel mitten in der
Sitzung werden abgelehnt: `SetPeerClientPublicKey` gilt nach dem Prinzip
erster Schreibzugriff gewinnt, und ein späterer, abweichender Schlüssel wird
geloggt und ignoriert (`connect/transfer_encrypt.go:1787-1816`).

### 7.3 Verifikation und die zwei Verteidigungen

- **Verteidigung 1, signierte Zertifikatsbindung.** Der Provider signiert
  seine ephemere TLS-Zertifikatskette mit seinem Ed25519-Schlüssel und
  veröffentlicht beides (`connect/protocol/transfer.proto:486-498`). Die
  Plattform hängt die Kette, die Signatur und den öffentlichen Schlüssel des
  Providers an jeden Vertrag, der diesen Provider benennt (`:340-368`,
  `:388-406`). Der Client lässt die Kette nur zu, wenn die Signatur unter dem
  öffentlichen Schlüssel des Providers verifiziert, und prüft dann das im
  Handshake vorgelegte Zertifikat gegen die zugelassene Kette
  (`connect/transfer.go:3930-3934,4006-4018`).
- **Verteidigung 2, Identitätsnachweis im Handshake.** Nach dem TLS-Handshake
  signiert jede Seite die RFC-5705-Exporter-Ausgabe unter dem Label
  `urnetwork-sequence-identity-proof` und sendet sie als `EncryptedControl`
  (`connect/protocol/transfer.proto:460-476`). Das AEAD wird dem Wrap-Pfad
  vorenthalten, bis der Nachweis des Peers verifiziert
  (`connect/transfer_encrypt.go:1492-1498`, `:1719-1756`), ein MITM, der TLS
  auf der einen Etappe terminiert und auf der anderen neu handshaked, erzeugt
  also nicht zusammenpassende Exporter und kann die Signatur nicht fälschen.

Beide Verteidigungen prüfen gegen `peerClientPublicKey` — und dieser Wert
stammt aus dem von der Plattform verfassten Vertrag
(`connect/transfer.go:6119-6129`; `connect/transfer_encrypt.go:1780-1791`).

### 7.4 Kann der Operator einen Provider-Schlüssel austauschen? Heute: ja.

**Klar gesagt: Ein Operator, der das Zertifikat, die Zertifikatssignatur und
`destination_client_public_key` im Gleichschritt austauscht, überwindet beide
Verteidigungen und kann sich als Maschine in die Mitte einer versiegelten
Sitzung setzen.** Die Design Notes sagen das in den eigenen Worten des
Repositorys (`connect/DESIGNNOTES.md` §3.7): *„Verbleibendes Loch: Eine
Plattform, die Zertifikat + Signatur + `destination_client_public_key` im
Gleichschritt austauscht, gewinnt auf der Seite der Zertifikatsbindung
weiterhin; der abschließende Zug besteht darin, `SetPeerClientPublicKey` aus
dem OOB-Lookup statt aus dem Vertrag zu speisen. Diese Gegenprüfung ist
derzeit nur ein Log-Eintrag.“*

Der vorgesehene abschließende Zug existiert und ist verkabelt, handelt aber
nicht. Eine nicht authentifizierte Route `GET /key/<client_id>` liefert den
veröffentlichten Schlüssel aus (`server/api/api.go:123-124`;
`server/controller/connect_controller.go:826-849`), und das ausgelieferte SDK
installiert dagegen für jeden Fenster-Client und jeden Provider-Client einen
Fetcher pro Sitzung (`sdk/device_local_provider.go:398-420`, erreicht von
`sdk/device_local.go:3434` und `:90`). Beim ersten Setzen des Schlüssels holt
der Client den Schlüssel des Peers out of band und vergleicht. Bei Abweichung
loggt er:

```
CONTRACT vs FETCHED peer client public key MISMATCH for <peerId>
— possible platform MITM (today: log only, contract value still trusted)
```

(`connect/transfer_encrypt.go:1871-1876`). Dem vom Vertrag gelieferten
Schlüssel wird weiterhin vertraut (`:520-525`, `:1839-1849`). Vom Loggen zum
Ablehnen überzugehen wird sowohl im Kommentar der Einstellungen als auch in
den Design Notes als nächster Härtungsschritt beschrieben — das ist
**Designabsicht**, keine ausgelieferte Eigenschaft.

Drei weitere Präzisierungen, die ein Auditor im Kopf behalten sollte:

1. **Der Out-of-Band-Kanal ist out of band gegenüber der Vertrags-Pipeline,
   nicht gegenüber dem Operator.** Der Abruf geht an denselben API-Host des
   Operators (`sdk/device_local_provider.go:404`) und liest dasselbe Redis,
   das der Verfasser des Vertrags beschreibt. Selbst nachdem aus Loggen
   Ablehnen geworden ist, erwischt die Prüfung einen Operator, der *zwischen
   zwei seiner eigenen Kanäle inkonsistent ist*, nicht einen, der konsistent
   ist. Das zu schließen erfordert einen Anker, den der Operator nicht
   kontrolliert — aus Schlüsseln abgeleitete IDs oder ein Transparency Log,
   beide als zurückgestellt vermerkt.
2. **Weglassen ist so wirksam wie Austauschen, und leiser.** Die
   Zertifikatsprüfung wird ohne Verriegelung übersprungen, wenn die vertraute
   Menge leer ist, auch dann, wenn Verträge ein leeres
   `ProvideTlsCertificate` tragen (`connect/transfer.go:4010-4016`), und der
   Identitätsnachweis lässt sich überhaupt nicht verifizieren, wenn der
   öffentliche Schlüssel des Peers fehlt
   (`connect/transfer_encrypt.go:1706-1708`). So oder so wird der Cipher nie
   nutzbar, und der Datenverkehr läuft im Klartext (§2.2), ohne für den
   Nutzer sichtbares Signal. Ein Operator, der den Datenverkehr eines
   bestimmten Nutzers lesen will, während der Schalter an ist, muss nichts
   fälschen; er muss ein Feld weglassen.
3. **Auch die Echtheit des Vertrags wurzelt im Operator.** Ein Provider
   verifiziert das HMAC des Vertrags mit einem geheimen
   Bereitstellungsschlüssel, den der Provider erzeugt und der Plattform
   bekannt gibt (`server/controller/connect_controller.go:768-779`;
   `sdk/device_local.go:2866-2872`). Der Operator hält eine Kopie, und genau
   das erlaubt ihm überhaupt erst, Verträge zu verfassen. Das ist von einer
   Abrechnungsinstanz zu erwarten, aber es heißt, dass „der Vertrag ist echt“
   keine vom Operator unabhängige Aussage ist.

**Was das untergräbt und was nicht.** Es rührt nicht an die Blindheit des
Providers für deine Identität, die von keiner Schlüsselverteilung abhängt. Es
heißt aber, dass die Blindheit des Operators für Inhalte auf dem versiegelten
Pfad derzeit darauf ruht, dass der Operator Schlüssel ehrlich verteilt — was
eine Eigenschaft der *Richtlinie* ist, mit einem kryptografischen Mechanismus
dahinter, der den größten Teil des Weges gebaut ist, und noch keine
Eigenschaft, die gegen einen feindseligen Operator hält. Jedes
URnetwork-Dokument, das die versiegelte Sitzung so beschreibt, als mache sie
die Blindheit des Operators bedingungslos, übertreibt, und dieses Dokument
ersetzt eine solche Formulierung.

## 8. Timing- und Verkehrskorrelation und der globale passive Beobachter

### 8.1 Es gibt keine Abwehr gegen Verkehrsanalyse. Keine.

URnetwork liefert auf Nutzerdaten **keinen Cover-Traffic, kein Padding, kein
Mixing, keine Batching-Verzögerung und kein Traffic Shaping** aus. Das wurde
erschöpfend über `connect`, `sdk` und `server` geprüft:

- Nirgends existiert ein Generator für Chaff, Köder, Dummy- oder
  Cover-Traffic.
- Das AEAD ist konstruktionsbedingt längenerhaltend: Die Chiffretextlänge ist
  Nonce + Klartext + Tag (`connect/transfer_encrypt.go:305,340`). Kein
  Protobuf in `connect/protocol/` trägt ein Padding-Feld, und das Framing ist
  ein nacktes 4-Byte-Längenpräfix (`connect/message_framer.go:28-31`).
- Das Zusammenfassen auf der Sendeseite ist ausdrücklich verzögerungsfrei:
  *„Es gibt keine Batching-Wartezeit: Die Sequenz nimmt ein zweites Pack nur,
  wenn es bereits in der Warteschlange steht“* (`connect/transfer.go:387-392`).
  Jedes `jitter` in den Bäumen ist Reconnect-Backoff oder Streuung der
  Kanallebensdauer, kein Traffic Shaping. Die Ack-Kompression
  (`connect/transfer.go:272`) verzögert allein Quittungen, um das
  Nachrichtenvolumen im Relay zu senken.
- Die einzige Stelle, an der Nutzerdatenverkehr überhaupt getaktet wird, ist
  die Obergrenze `WritePacketsPerSecond` des DNS-förmigen Transports
  (`connect/transport_pt.go:63,232-246`), die es gibt, um resolverfreundlich
  zu sein, und die nur für den am wenigsten bevorzugten Transportmodus gilt.
  Seine „Pump“-Anfragen im Leerlauf haben eine von datentragenden
  unterscheidbare Länge, er verbirgt also weder Größe noch Rate.

**Daher: Ein Angreifer, der den Datenverkehr beobachtet, der in dein Gerät
eintritt, und den Datenverkehr, der die Provider verlässt, die ihn tragen,
kann beides über Größe und Timing korrelieren. Gegen diesen Angreifer schützt
URnetwork nicht.** Das ist dieselbe Aussage, die Tor über
Ende-zu-Ende-Korrelation trifft, und sie gilt hier mit weniger Spielraum,
denn URnetworks Designziel ist niedrige Latenz — und genau diese Eigenschaft
macht Korrelation leichter. Ein latenzbegrenzter Pfad aus vier Etappen ist
ein bewusster Tausch gegen die zusätzliche Verzögerung eines Mixnets, und das
ist die Seite dieses Tauschs, die der Nutzer bezahlt. Die Extender-Etappe
mitzuzählen ändert daran nichts: Dieser Hop leitet die verschlüsselte Sitzung
an den Operator weiter, ohne sie zu terminieren, er fügt also keine Schicht
hinzu, die ein Beobachter abziehen könnte, und keine Verzögerung, in der er
dich verlieren könnte.

Zwei Dinge werden bisweilen für Abwehrmaßnahmen gehalten und sind keine.
Extender und die geformten Transporte (`connect/net_resilient.go:112-215`,
`connect/transport_pt.go:18-45`) zielen auf DPI-gestützte Sperren, und die
Resilienz-Schicht schaltet sich selbst ab, sobald der Stream steht
(`net_resilient.go:102,146-161`) — sie rührt Records der Datenphase nie an.
TLS-Session-Ticket-Caches werden bewusst nicht zwischen Ausgangspfaden
geteilt, damit ein Server sie nicht über ein eingelöstes Ticket verknüpfen
kann (`connect/net_tls.go:38-42,99-103`); das ist Unverknüpfbarkeit von
Tickets, keine Verkehrsanalyse.

Nichts im Quellcode erkennt Verkehrskorrelation als Einschränkung an: Eine
Suche nach `traffic analysis`, `timing correlation`, `traffic correlation`
und `global adversary` über alle drei Bäume liefert null Treffer. Das
Bedrohungsmodell im Repo (`connect/DESIGNNOTES.md` §3.7) dreht sich
ausschließlich um den MITM durch den Operator. Dieses Dokument ist die erste
Stelle, an der die Lücke aufgeschrieben ist.

### 8.2 Das Mehr-Provider-Fenster ist kein Mechanismus gegen Korrelation

Der Datenverkehr tritt normalerweise über mehrere Provider zugleich aus —
üblicherweise drei bis acht über die beiden Fenster — und die Bindung pro
Website hält eine bestimmte Website auf einem Provider
(`connect/ip_remote_multi_client.go:138-158,1234-1240`). Das begrenzt
tatsächlich, wie viel ein einzelner Exit sieht. Aber die Designbegründung des
Fensters im Quellcode ist durchweg Zuverlässigkeit — Abfederung schlechter
Ziele, gesundheitsgewichtete Größenanpassung, Blackhole-Erkennung
(`:27-52`) —, und der eine Kommentar, der „geringere Bindung ist privater“
lautet, sitzt auf `ClientAffinityTimeout`, einem Regler, der
**auskommentiert** ist (`:587-591`, und noch einmal in den Standardwerten bei
`:220`), während `DestinationAffinity` aus Gründen der Zuverlässigkeit auf
true ausgeliefert wird (`:270`). Plurale Exit-Identität ist ein echter
Vorteil, und es ist fair, ihn zu behaupten; sie als geplante Abwehr gegen
Korrelation zu behaupten, wird vom Code nicht gestützt.

### 8.3 Der globale passive Beobachter: außerhalb des Geltungsbereichs

Ein globaler passiver Angreifer — einer, der einen großen Teil der
Internetverbindungen gleichzeitig beobachten kann — **liegt außerhalb des
Geltungsbereichs, und URnetwork bietet keine Abwehr gegen ihn.** Ohne Padding
und ohne Cover-Traffic korreliert ein solcher Angreifer Flows über das Relay
und die Provider hinweg direkt. Das ist dieselbe Position, die Tor einnimmt,
und anders als Tor fügt URnetwork nicht einmal eine Verzögerung pro Hop
hinzu, die die Kosten erhöhen würde.

Was wirklich anders ist und sich zu sagen lohnt, ohne es aufzublasen: Die
Ausgangsmenge ist eine ständig wechselnde Population unabhängiger
Privatanschlüsse und nicht die veröffentlichten Adressbereiche eines
Operators, ein Angreifer muss also eine breitere und sich verschiebende Menge
von Endpunkten beobachten, um einen einzelnen Nutzer abzudecken, und die
Endpunkte lassen sich nicht aus einer Serverliste aufzählen. Das erhöht die
Kosten. Es ändert das Ergebnis für einen Angreifer nicht, der beide Enden
ohnehin sehen kann.

## 9. Gerätekennungen und Verknüpfbarkeit

### 9.1 Was ein Provider über dich beobachten kann

**Die `SourceId` des Vertrags ist eine Client-ID pro Fensterplatz, nicht dein
Gerät.** `StoredContract.SourceId` ist die `client_id` des authentifizierten
Aufrufers (`server/controller/connect_controller.go:461-463`; vom Provider
geparst bei `connect/transfer.go:6088-6106`). Der Generator prägt für jeden
Fenstereintrag eine frische Client-ID, ein frisches JWT und eine frische
Instanz-ID und entfernt sie beim Abbau — der Quellcode sagt das direkt:
*„Der API-Generator prägt für jeden Fenstereintrag eine ephemere
Plattform-Client-ID (mit frischer Instanz-ID) und entfernt sie beim Abbau“*
(`connect/ip_remote_multi_client_identity.go:10-15`; geprägt bei
`connect/ip_remote_multi_client_api.go:326-345`, freigegeben bei
`:410,473`).

**Aber diese Identitäten werden bewusst bis zu vier Stunden lang
wiederverwendet, auf jedem Pfad — nicht nur auf gehosteten.** Das Gerät
installiert seinen eigenen lokalen Identitätsspeicher, sofern es nicht
gehostet ist (`sdk/device_local.go:1204-1208`), und eine gespeicherte
Fenster-Identität wird gegenüber demselben Ziel erneut abgespielt, bis sie
veraltet: `windowIdentitiesStaleAfter = 4 * time.Hour`
(`sdk/window_identity_store.go:44-52`). Der Zweck ist, die NAT-Flows eines
Providers über einen Neustart hinweg am Leben zu halten
(`connect/ip_remote_multi_client_identity.go:17-23`). Der Preis ist, dass ein
Provider dieselbe `SourceId` innerhalb dieses Fensters über App-Neustarts
hinweg von dir wieder auftauchen sehen kann. Sag vier Stunden, nicht
„ephemer“.

**Der Ed25519-Identitätsschlüssel des Clients ist auf dem Ausgangspfad pro
Fenster-Client frisch.** Die Einstellungen der Fenster-Clients werden aus
einem frischen `DefaultClientSettingsWithBufferSize` gebaut
(`sdk/device_local.go:3434-3437`), das keinen `ClientKeySeed` trägt
(`connect/transfer.go:166-183`), also erzeugt `ClientKeyManager` ein neues
Schlüsselpaar (`connect/transfer_key.go:96`). Der persistierte
Fenster-Snapshot speichert nur Client-ID, JWT und Instanz-ID — keinen
Schlüssel-Seed (`sdk/window_identity_store.go:46-52`), eine
wiederhergestellte Identität veröffentlicht also einen neuen Schlüssel. Ist
die Post-Quanten-Verschlüsselung aus, wird überhaupt kein Identitätsnachweis
vorgelegt (`connect/ip_remote_multi_client.go:9149-9157`).

**Die Quelladresse im Tunnel gilt pro Sitzung und hat wenig Entropie.** Das
SDK weist seinem TUN eine zufällige RFC1918-Adresse zu — „eine zufällige
10.x.y.h (RFC1918, DHCP-förmig)“ (`sdk/device_local.go:566-571,1070-1090`) —,
erzeugt mit einem Host-Oktett in 2..254 über dem kleinsten kollisionsfreien
`10.a.b.0/24` (`connect/tun.go:323-348`). Sie wird im Konstruktor berechnet
und nie persistiert, sie ändert sich also mit jeder Sitzung. Der Provider
sieht sie **sehr wohl**: Sie ist das Quellfeld jedes getunnelten Pakets, und
der Provider führt seinen NAT-Zustand danach
(`connect/ip.go:742,1009-1020,1151`). Rund 253 Werte sind ein schwacher
Fingerabdruck pro Sitzung, keine sitzungsübergreifende Kennung.

### 9.2 Der Identitätsschlüssel der Provider-Rolle ist dauerhaft

Wenn du auch deine Verbindung teilst, hält dein **Provider**-Client ein
langlebiges Ed25519-Schlüsselpaar, dessen Seed im lokalen Speicher
persistiert wird (`sdk/local_state.go:418-461`,
`.device_local_key_material`, JSON `client_key_seed`; angewandt bei
`sdk/device_local_key_material.go:54-70`). Anders als die Fenster-Clients
bleibt dieser Schlüssel **bewusst über eine automatische Abmelde-Bereinigung
hinweg erhalten** — der Android-Kommentar ist eindeutig: *„Einen veralteten
oder unvollständigen Auth-Zustand löschen, OHNE die Geräteidentität zu
rotieren. Das Identitätsschlüsselmaterial gilt geräteweit, nicht
sitzungsweit“* (`android/.../MainApplication.kt:636-647`). Token-Erneuerung,
Wiederherstellung nach unvollständiger Anmeldung und die erneute Anmeldung
nach 30 Tagen Untätigkeit erzeugen daher eine neue `client_id` **und** eine
neue `device_id`, während der öffentliche Ed25519-Schlüssel derselbe bleibt.
Nur eine ausdrückliche Abmeldung durch den Nutzer rotiert ihn
(`sdk/local_state.go:639-644`).

Dieser Schlüssel ist veröffentlicht, in jeden Vertrag eingeschlossen, der
diesen Client als Ziel benennt
(`server/controller/connect_controller.go:413-415,468`), und für jeden
lesbar: `GET /key/<client_id>` ist von Haus aus nicht authentifiziert
(`server/api/api.go:123-124`;
`server/controller/connect_controller.go:826-829`). Jede Partei — nicht nur
ein Provider, den du bedient hast — kann also jede Client-ID zu ihrem
öffentlichen Schlüssel auflösen und die Client-IDs zusammenfassen, die sich
einen teilen. Für ein Provider-Konto ist das eine dauerhafte Handhabe über
Sitzungen, über `client_id` und über `device_id` hinweg. Das ist ein echter
Preis des Bereitstellens, und er ist nirgendwo sonst im Korpus dokumentiert.

### 9.3 Beim Operator verknüpft sich alles

- Eine `client_id` wird nie widerrufen. Der Kommentar im Code selbst:
  *„client_ids sind global eindeutige Adressen, gleichbedeutend mit IPv6 /
  sie werden nach der Zuteilung nie widerrufen, um Sicherheits- und
  Audit-Datensätze zu bewahren“*
  (`server/model/network_client_model.go:64-67`). Ein Top-Level-Client wird
  nach 30 Tagen Untätigkeit deaktiviert (`TopLevelClientIdleExpiration`,
  `:2289`) und 30 Tage danach hart gelöscht
  (`NetworkClientReapAfterDeactivate`, `:2269`), kaskadierend auf die
  Gerätezeile und den Redis-`ckey` (`:2537`).
- Eine `device_id` gilt **pro Anmeldung**, nicht pro Hardware oder pro
  Installation: Mit jedem Top-Level-Client wird eine frische geprägt
  (`:332-352`), und der Code vermerkt den daraus folgenden
  „Identitätswechsel (eine frische device_id pro Anmeldung)“ (`:2280`).
  Fenster-Clients erben sie (`:356-380`), und sie wird nie an einen Provider
  gesendet.
- Das Netzwerk-Token ist ein JWT mit 24 Stunden Laufzeit
  (`server/jwt/by_jwt.go:35-37,188`), vom SDK bei Halbwertszeit erneuert —
  nach etwa 12 Stunden — mit Jitter
  (`sdk/device_token_manager.go:107-124,165`). **Das Token zu erneuern
  rotiert die Client-ID nicht**; derselbe Claim wird neu geprägt
  (`server/model/network_client_model.go:102-125`).
- `audit_contract_event` verzeichnet Client- und Provider-Identität je
  Vertrag (`server/db_migrations.go:234-251`). `client_reliability` verbindet
  den Block-Hash mit geheimem Schlüssel direkt mit einer Client-ID, pro
  Block: Der ursprüngliche vierspaltige Primärschlüssel
  (`server/db_migrations.go:2083-2106`) wurde später auf
  `(block_number, client_address_hash, client_id)` reduziert
  (`:2191-2195`), und die aktive partitionierte Tabelle nutzt dieselben drei
  (`server/model/network_client_reliability_partition_model.go:194-195`),
  wobei `network_id` als Index-Payload überlebt (`:63,631-634`). Die
  Aufbewahrung beträgt 30 Tage
  (`server/model/network_client_reliability_model.go:42,687-721`;
  Tagespartitionen werden als Ganzes verworfen).
- `network_client.auth_time` ist ein dauerhaftes Zuletzt-gesehen, 30 Tage
  aufbewahrt (`server/model/network_client_model.go:2269,2289`); Zeilen
  getrennter Verbindungen werden nach 8 Stunden abgeräumt
  (`server/taskworker/work/network_client_work.go:85`).
- Kennungen auf Kontoebene, allein beim Operator: E-Mail-Adresse oder
  Telefonnummer im Klartext in `network_user.user_auth`, das vollständige JWT
  des Drittanbieter-IdP bei SSO-Anmeldungen, Kennungen im Klartext für jeden
  Anmeldeversuch in `user_auth_attempt`, Wallet-Adressen, Zahlungszeilen,
  eine dauerhafte Wer-hat-wen-eingeladen-Kante `network_referral` und
  `audit_provider_event`-Zeilen, die wörtliche Land-, Regions- und
  Stadt-Strings gegen `network_id` und `device_id` tragen, nicht an das
  8-Stunden-Abräumen der Verbindungen gebunden
  (`review/verified/PRIVACY-ENFORCEMENT.md` §1.4).
- `User-Agent` wird von der Allowlist aus fünf Headern geloggt
  (`server/http_log.go:15-29`). Er ist der eine Eintrag der fünf, der eine
  Fingerprinting-Fläche ist.

### 9.4 Die WireGuard-Brücke verknüpft dich über Provider hinweg

Jedem WireGuard-Client wird eine stabile private Tunnel-Adresse aus einem
durchmischten Pool von 10.000.000 RFC1918-Adressen zugeteilt
(`server/model/network_client_proxy_model.go:1034,1038-1118`), in die
Konfiguration als Adresse der Schnittstelle geschrieben (`:756-771`), und sie
wird **vor dem Ausgang nicht normalisiert** — das FIXME im Quellcode selbst
lautet *„derzeit wird die Client-IPv4 zu den Ausgangs-Providern
durchgereicht / das kann es erlauben, eine einzelne Client-IPv4 über mehrere
Provider hinweg zu verfolgen“* (`proxy/wg.go:23-25`). Es ist eine private
Adresse, nicht deine echte IP, und die Ziel-Website sieht sie nie. Aber jeder
Provider in deinem Fenster sieht dieselbe Quelladresse, **kolludierende
Provider können also erkennen, dass diese Flows zu einem Client gehören** —
genau die Eigenschaft, die das Mehr-Provider-Fenster ansonsten liefert.
Zusammen mit dem festen Resolver `1.1.1.1` (§3.2) und dem Fehlen einer
versiegelten Sitzung auf diesem Pfad ist die WireGuard-Brücke der am
wenigsten private Weg, das Netzwerk zu nutzen. Die Apps und das SDK sind der
privateste.

## 10. Rechtliche Anordnungen

**Gerichtsstand.** BringYour, Inc. ist eine Delaware-Kapitalgesellschaft
(`docs/legal/ur.xyz/terms.md:16,25`) mit einer Postanschrift in San Francisco
(`docs/legal/terms.md:269-271`). Die ur.io-Bedingungen legen anwendbares
Recht und Gerichtsstand auf Harris County, Texas, fest
(`docs/legal/terms.md:315-321`); die ur.xyz-Bedingungen legen Delaware fest
(`ur.xyz/terms.md:223-229`). Alles davon liegt in den USA, und alles davon
ist durch US-Zwangsverfahren erreichbar, einschließlich Verfahren, die mit
einer Schweigeverfügung kommen. Die Bedingungen erklären, dass der Operator
„Informationen überwachen und offenlegen darf, wo Gesetz oder behördliche
Anordnung dies verlangen“ (`docs/legal/terms.md:204-206`).

**Was eine Anordnung an den Operator erreicht.** In absteigender Reihenfolge
der deanonymisierenden Kraft: wer das Konto ist — E-Mail-Adresse oder
Telefonnummer im Klartext, das JWT des Drittanbieter-IdP bei
SSO-Anmeldungen, Wallet-Adressen und Zahlungsdatensätze, die über Stripe,
Apple, Google Play oder eine `tx_signature` on-chain an eine echte Identität
binden; wann es sich verbunden hat und aus welcher Stadt, pro Verbindung;
welche Provider es genutzt hat und für wie viele Bytes; und einen Hash mit
geheimem Schlüssel über den /29- oder /56-Block, aus dem es sich verbunden
hat, dazu den Quellport im Klartext. Dritte halten mehr: Die in §1 genannten
Zahlungsdienstleister halten Identität, die der Operator nie speichert, und
eine Solana-`tx_signature` löst sich zu einer Wallet auf einer öffentlichen
Chain auf.

**Was eine Anordnung nicht erreicht, weil es nicht existiert.** Das
Transferregister hat nirgends ein Feld für Ziel, Host, URL, SNI, Port oder
Domain (`review/verified/PRIVACY-ENFORCEMENT.md` §1.2). Hochgeladene
Support-Logs werden beim Empfang verworfen. Es gibt keinen Browserverlauf
herauszugeben, auf keinem Pfad, versiegelt oder nicht — das ist die stärkste
strukturelle Eigenschaft in diesem Dokument, und sie gilt unabhängig davon,
ob sich jemand anständig verhält.

**Was eine Anordnung mit Blick nach vorn erreicht.** Alles bisher Gesagte
betrifft gespeicherte Datensätze. Eine Anordnung, die künftiges Verhalten
erzwingt, ist etwas anderes, und §7.4 ist die Stelle, an der sie greift: Ein
Operator, der gezwungen wird, einen bestimmten Nutzer abzuhören, könnte heute
Provider-Schlüsselmaterial austauschen oder weglassen und den Datenverkehr
dieses Nutzers lesen, selbst bei eingeschalteter
Post-Quanten-Verschlüsselung, wobei das einzige Signal eine Zeile im
Gerätelog wäre. Die versiegelte Sitzung erhöht die Kosten rückwirkender
Offenlegung. Sie widersteht in ihrer heutigen Form keinem gezwungenen
Operator mit Blick nach vorn.

**Die Kontolöschung ist unvollständig.** `RemoveNetwork` ist eine von Hand
geschriebene Löschliste, keine Datenbank-Kaskade
(`server/model/account_model.go:108-260`). Sie entfernt die
`network_user`-Zeilen und ihre Auth-Datensätze (Passwort, SSO, Wallet,
Seedphrase), die `network`-Zeile und den Eintrag im Namensindex, und sie
plant eine Stripe-Kündigung ein. Sie löscht nicht `account_payment`,
`stripe_customer`, `apple_subscription_transaction`, abgeschlossene
`solana_payment_intent`-Zeilen, `network_referral`, Gerätezeilen oder
Audit-Zeilen; die altern nach ihren eigenen Zeitplänen aus — Audit-Ereignisse
nach 180 Tagen (`server/model/audit_model.go:984,1018`) — oder, bei
abgeschlossenen On-Chain-Zahlungen, gar nicht
(`server/model/solana_payment_intent_model.go:386-400` löscht nur Intents mit
einer `tx_signature` von null). Die Löschung *schreibt* außerdem eine Zeile:
ein `AuditEventTypeNetworkDeleted`-Ereignis, geschlüsselt auf die gelöschte
`network_id` (`account_model.go:255-257`). Das „Konto und die zugehörigen
persönlichen Daten löschen“ der Datenschutzerklärung
(`docs/legal/privacy.md:69`) ist weiter gefasst als das, was der Code tut.

**Es gibt keinen Warrant Canary, keinen Transparenzbericht und kein
veröffentlichtes Verfahren für Strafverfolgungsbehörden.** Als fehlend
verifiziert über `docs/` und den Quellcode der ur.io-Website. Der einzige
Hinweis auf ein Rechtsverfahren irgendwo verweist denjenigen, der
Schriftstücke zustellt, darauf, den Delaware Registered Agent bei der
Delaware Division of Corporations zu erfragen
(`docs/legal/ur.xyz/terms.md:262`); `security@ur.io` ist auf
Schwachstellenmeldungen begrenzt (`docs/legal/vdp.md:42`), und
`notice@ur.io` ist die allgemeine Adresse für vertragliche Mitteilungen.
URnetworks eigene Vergleichsdokumente räumen das gegenüber Mitbewerbern, die
eines veröffentlichen, bereits ein, und dieses Dokument wiederholt es, statt
es abzumildern.

**Die Datenschutzerklärung schweigt, wo sie konkret sein müsste.** Sie
erklärt, „alle persönlichen Informationen, die wir von und über Nutzer
erheben, beschränken sich auf E-Mail-Adresse oder Telefonnummer“, und die
Erhebung geschehe „direkt von dir, wenn du sie angibst“
(`docs/legal/privacy.md:29-37`).

Ein früherer Entwurf dieses Abschnitts nannte das eine zu knappe Beschreibung
des Systems, mit der Begründung, der Code speichere mehr Kategorien, als die
Erklärung benennt. Diese Einordnung wurde am 2026-08-09 als falsch
zurückgezogen. Alles andere, was dieses Dokument inventarisiert, sind
entweder Kontodaten, die der Nutzer durch Registrieren oder Bezahlen selbst
erzeugt (den Stripe-Verknüpfungsschlüssel gibt es, weil jemand zugestimmt
hat, abgerechnet zu werden), oder gar keine persönlichen Informationen: ein
Quellport und ein Block-Hash mit geheimem Schlüssel, den der Operator nicht
umkehrt. Ob ein Hash mit geheimem Schlüssel im Prinzip von seinem eigenen
Inhaber invertiert werden könnte, ist ein echter technischer Vorbehalt — §5
benennt ihn, und die fehlende Rotation ist eine echte Schwäche —, aber ein
Wert, den niemand nachschlägt, ist keine Kategorie persönlicher
Informationen, die zu deklarieren die Erklärung versäumt hätte.

Was der Erklärung tatsächlich fehlt, ist etwas anderes und Engeres: **keine
Aufbewahrungsfrist, keine Aussage zum Logging und kein Abschnitt zu
Strafverfolgung oder behördlicher Offenlegung.** Die Zeichenketten
*retention*, *log*, *IP address*, *subpoena* und *legal process* tauchen in
ihr nicht auf. Das fällt ins Gewicht, weil die Aufbewahrungsdisziplin im Code
existiert und stärker ist, als die Erklärung behauptet — §5.1 legt die
verifizierten Fenster dar. Ein Nutzer, der die Erklärung heute liest, kann
den Operator an keinem von ihnen festhalten.

## 11. Wogegen URnetwork nicht schützt

Drei Dinge gelten, und es lohnt sich, sie vor der folgenden Liste zu
benennen, damit die Liste als Grenze gelesen wird und nicht als Urteil. Auf
einem Relay-Pfad erfährt ein Provider nie, wer du bist, und keine Einstellung
und kein Provider-Build ändert das (§2). Es gibt nirgends im Transferregister
ein Feld für Ziel, Host, URL, SNI, Port oder Domain, es gibt also keinen
Browserverlauf, den man erzwingen, leaken oder verkaufen könnte (§5, §10).
Und jede einzelne dieser Aussagen ist in öffentlichem Quellcode nachlesbar,
und deshalb kann dieses Dokument bei den eigenen Fehlern konkret werden.

Alles Folgende ist ein Versagen. Ohne Absicherungen benannt; jeder Punkt ist
oben ausgeführt.

1. **Ende-zu-Ende-Timing- und -Verkehrskorrelation.** Kein Padding, kein
   Cover-Traffic, kein Mixing. Ein Angreifer, der sowohl dein Zugangsnetz als
   auch die Provider beobachtet, die deinen Datenverkehr tragen, kann beides
   korrelieren. §8.1.
2. **Ein globaler passiver Angreifer.** Vollständig außerhalb des
   Geltungsbereichs. §8.3.
3. **Kollusion zwischen Operator und Provider.** Der Operator weiß, wer du
   bist, der Provider weiß, wohin du gegangen bist, und der
   Vertragsdatensatz verbindet beides. Die Versiegelung verengt, was der
   Operator allein hält; sie zerbricht die Verbindung nicht. §6.2.
4. **Ein gezwungener oder feindseliger Operator, der
   Provider-Schlüsselmaterial austauscht oder weglässt.** Heute loggt die
   Gegenprüfung, die das erwischen würde, und macht weiter. §7.4.
5. **Stilles Downgrade der versiegelten Sitzung — BEI AUSGESCHALTETER
   Post-Quanten-Verschlüsselung.** In diesem Modus fällt jeder Fehlschlag
   (Handshake, Identitätsnachweis, fehlender Schlüssel) auf Klartext zurück,
   ohne für den Nutzer sichtbaren Hinweis. **Behoben für den Modus, der
   danach verlangt, am 2026-08-10:** Ist der Schalter an, läuft der Client
   fail-closed und weigert sich, Anwendungsdaten im Klartext zu senden oder
   anzunehmen. Was in beiden Modi bestehen bleibt, ist die fehlende Anzeige —
   keine App zeigt, ob eine gegebene Verbindung versiegelt ist. §2.2.
6. **Ein feindseliger Provider, der unverschlüsselten Datenverkehr
   manipuliert.** HTTP im Klartext wird unverändert durchgereicht; der
   Provider steht in der Position eines feindseligen Hotspots. §3.
7. **Kompromittierung des Endpunkts.** Schadsoftware, ein kompromittiertes
   Betriebssystem, eine feindselige Browser-Erweiterung oder jeder, der dein
   entsperrtes Gerät in der Hand hat. Nichts an einem Netzwerkprodukt geht
   das an.
8. **Identifizierung auf der Zielseite.** Cookies, Anmeldungen,
   Browser-Fingerprinting und Kontoverhalten identifizieren dich gegenüber
   den Websites, die du besuchst, unabhängig davon, wie die Pakete angekommen
   sind. Deine Exit-Adresse zu wechseln macht dich gegenüber einem Dienst,
   bei dem du dich anmeldest, nicht anonym.
9. **Identität über den Zahlungsweg.** Karten- und App-Store-Wege legen deine
   Identität beim Zahlungsdienstleister ab, auch wenn der Operator sie nicht
   speichert. On-Chain-USDC hinterlässt eine öffentliche `tx_signature`.
10. **Sybil-Provider.** Bereitstellen kann jeder, ohne Attestierung und ohne
    Stake. Eine einzelne Partei kann viele Provider betreiben, auch der
    Operator.
11. **Das Fehlen einer Versiegelung auf dem Browser- und dem Proxy-Pfad.**
    Die Browser-Erweiterung hat keine Einstellung für
    Post-Quanten-Verschlüsselung, und auf diesen Pfaden betreibt der Operator
    den Client. §2.4.
12. **Verknüpfbarkeit über Provider hinweg auf der WireGuard-Brücke.** Eine
    stabile Tunnel-Adresse über jeden Provider in deinem Fenster hinweg.
    §9.4.
13. **Eine dauerhafte Handhabe zur Identität für jeden, der auch
    bereitstellt.** Der Ed25519-Schlüssel des Provider-Clients überlebt
    gewollt die Rotation von Client-ID und Geräte-ID, und
    `GET /key/<client_id>` ist nicht authentifiziert, jede Partei kann also
    Client-IDs zusammenfassen, die sich einen Schlüssel teilen. §9.2.
14. **Datenverkehr, den das lokale Netzwerk im DNS-Fenster beim Start
    sieht.** Im Quellcode als hingenommener Preis dokumentiert. §3.2.
15. **Alles, was eine externe Prüfung gefunden hätte.** Für das Protokoll und
    den Server-Code wurde keine durchgeführt.

## 12. Was dieses Dokument nicht klären konnte

Eine ungeklärte Behauptung in einem Bedrohungsmodell ist eine Behauptung, die
auch nicht in der Dokumentation stehen sollte. Diese sind offen.

- **Was der Ingress-LB loggt.** Die nginx-Header-Konfiguration liegt im Baum
  (`xops/.../connect/ingress.yaml:9`), und der Connect-Dienst begrenzt die
  Rate anhand einer gehashten Adresse
  (`server/connect/transport_rate_limit.go:65-80`), aber die
  Zugriffslog-Konfiguration von nginx selbst wurde nicht auditiert. Jede
  durchgängige Aussage „wir bewahren deine Adresse nicht auf“ hängt daran.
- **Ob die nicht von der Verbosität abhängigen Log-Zeilen mit Adressen und
  SNI aus §5 dauerhaften Speicher erreichen.** Sie werden nach stderr
  geschrieben; wohin stderr in Produktion geht und wie lange es aufbewahrt
  wird, ist eine Frage des Deployments, die diese Quellcode-Durchsicht nicht
  beantworten kann. Der Monitoring-Tailer liest sehr wohl `ip:port`-Muster
  aus Log-Zeilen heraus und gibt sie erneut in Befunde aus
  (`server/monitor/tailer.go:136,328,333`), was ein Beleg dafür ist, dass
  zumindest einige dieser Zeilen von Systemen gelesen werden, die sie
  aufbewahren.
- **Ob das serverseitige WireGuard-Proxy-Gerät die Paketquelle umschreibt,
  bevor es Pakete an Provider übergibt.** Die stabile Tunnel-Adresse und die
  Sicht des Operators auf den echten öffentlichen Endpunkt
  (`server/proxy/wg_handoff.go:56-67`) sind beide verifiziert; der
  vollständige Pfad durch `server/proxy/proxy_device.go` und
  `OpenProxyDevice` wurde nicht von Anfang bis Ende gelesen
  (`review/verified/ARCHITECTURE.md`, nicht verifizierbarer Punkt 3).
- **Ob die Namensauflösung auf dem Browser-Pfad jemals lokal geschehen kann.**
  Die Erweiterung konfiguriert standardmäßig einen HTTPS-CONNECT-Proxy, der
  aus der Ferne auflöst, und die SOCKS-Namensauflösung läuft über den
  DoH-Dialer des Tunnels (`connect/tun.go:1155-1175`). Das
  Proxy-DNS-Verhalten je Browser unter jeder Konfiguration wurde nicht
  getestet.
- **Die tatsächliche Verbosität in Produktion.** `BY_LOG_V` steht
  standardmäßig auf 0 (`server/env.go:41-49`), was das an `V(1)` gebundene
  Ziel-Logging auf Client und Server unterdrückt — aber das einzige
  Deployment-Manifest im Baum setzt es auf `2`
  (`xops/gitops-unused/.../api/deployment.yaml:47-48`), in einem Verzeichnis
  namens `gitops-unused`. Behandle Verbosität als Laufzeit-Flag, nie als
  strukturelle Garantie.
- **Unabhängigkeit der Flotte.** Der Operator veröffentlicht Live-Zahlen zu
  Städten und Ländern aus der eigenen Aggregation über aktuell verbundene,
  gültige Provider (`server/model/network_client_location_model.go:1607-1641`),
  und der Standort wird vom Operator aus der Verbindung abgeleitet, die er
  beobachtet, statt vom Provider deklariert zu werden
  (`review/verified/ARCHITECTURE.md` §6.4). Aber keine unabhängige Partei hat
  die Flotte von außen vermessen, und nichts weist nach, dass die einem
  bestimmten Client angebotenen Provider voneinander oder vom Operator
  unabhängig sind. Der Mechanismus ist im Quellcode überprüfbar; die
  Population ist heute für eine dritte Partei nicht überprüfbar.
- **Die Bindung des Identitätsschlüssels bei der Kontoerstellung.** Das Design
  formuliert die Erwartung, dass „die Bindung (ClientId, öffentlicher
  Schlüssel) bei der Kontoerstellung registriert wird“
  (`connect/transfer_key.go:20-30`). Ausgeliefert wird ein Client, der seinen
  Schlüssel in ein vom Operator kontrolliertes Redis veröffentlicht, wieder
  ausgeliefert von einer vom Operator kontrollierten API. Ob betrieblich eine
  stärkere Registrierung existiert, ließ sich aus dem Quellcode nicht klären;
  geh davon aus, dass es sie nicht gibt.
- **Ob jeder Sendepfad des Geräts einen Fenster-Client nutzt.** Die ephemere
  Schlüsselvergabe des Fensterpfades ist verifiziert (§9.1). Der
  Top-Level-Client des Geräts trägt den dauerhaften Seed und aktiviert die
  Verschlüsselung bedingungslos (`sdk/device_local_provider.go:90-98`), jedes
  Senden, das auf dem Top-Level-Client reitet — Netzwerk-Peer-Beziehungen,
  Companion-Rückwege —, wird also mit dem stabilen Schlüssel signiert und
  trägt die stabile Top-Level-`client_id`. Diese Pfade wurden nicht
  erschöpfend aufgezählt. Lies „Ausgangskennungen sind ephemer“ als auf den
  Fenster-Client-Pfad begrenzt.
- **Ob `Roles` und `Principal` bei gewöhnlichen Verbraucher-Clients jemals
  gefüllt werden.** Es sind vom Operator zugewiesene Strings, die in die
  signierten Vertragsbytes eingeschlossen sind und nur für
  `ProvideMode_Network` gesetzt werden
  (`connect/protocol/transfer.proto:408-415`;
  `server/controller/connect_controller.go:474-481`). Es fand sich kein Beleg
  dafür, dass die Apps sie füllen, und nicht jeder Aufrufer wurde auditiert.
  Würden sie jemals für Verbraucher-Datenverkehr gefüllt, wären sie
  vollwertige sitzungsübergreifende Kennungen, die für einen Provider sichtbar
  sind.
- **Persistenz des Schlüsselmaterials auf nicht-mobilen Hosts.**
  `ClientKeySeed` wird nur aus `sdk/local_state.go`,
  `sdk/device_local_key_material.go`, `sdk/device_local.go` und `sdk/cgo/`
  referenziert. Hosts, die diese nicht aufrufen, bekommen pro Prozess einen
  frischen Schlüssel; das Verhalten von Linux, Windows, Erweiterung und
  Server-Proxy wurde nicht einzeln verifiziert.
- **Ob der Gerichtsstand Texas in den ur.io-Bedingungen beabsichtigt ist**,
  angesichts einer Delaware-Gesellschaft, einer kalifornischen Adresse und
  eines Gerichtsstands Delaware in den ur.xyz-Bedingungen. Kein Dokument im
  Baum erklärt das. Das ist eine Frage an die Rechtsberatung, kein Befund.

## 13. Meldungen

Schwachstellen: `security@ur.io` und die Offenlegungsrichtlinie unter
[ur.io/vdp](https://ur.io/vdp). Korrekturen an diesem Dokument,
einschließlich Widerspruch zu jedem Urteil darin, sind auf demselben Weg
willkommen — ein unabhängiger Befund, der einer Behauptung hier widerspricht,
ist nützlicher als die Behauptung.
