Lafine Systems Design · Technisches Dokument

Whitepaper zu RoamSwitch-Architektur und -Sicherheit

In diesem Dokument wird erläutert, mit welchen Privilegien RoamSwitch ausgeführt wird und was es an dieser Grenze tut. Es enthält keine Marketingsprache; Alles, was hier angegeben ist, kann mit der Versand-App überprüft werden Binärdatei und ihr tatsächliches Verhalten.

Version v1.5 Geltungsbereich RoamSwitch 1.9.47 (build 104) Voraussetzungen macOS 13.0+ / Apple Silicon Veröffentlicht 2026-09-15 Team ID GV76B6G4YU

§1

RoamSwitch ist eine Menüleisten-App für den Mac. Je nachdem, wie sehr Sie dem Netzwerk vertrauen, dem Sie vertrauen aktuell verbunden, schaltet es automatisch die macOS-Firewall, die Freigabedienste, AirDrop usw. um. und DNS. Es überwacht auch ARP-Spoofing, nach außen offene Ports, USB-Speicher usw Ransomware-ähnliche Verschlüsselungsaktivitäten, und wenn etwas Gefährliches entdeckt wird, geht es so weit Unterbrechen des Datenverkehrs mit dem Paketfilter (pf) – ein Notfall-Air-Gap.

Mit anderen Worten: RoamSwitch installiert einen Root-privilegierten Daemon und könnte, wenn er wollte, alle stoppen Netzwerkverkehr auf dem Mac. Es wird von einer Person gebaut und „Bitte vertrau mir“ reicht nicht aus rechtfertigen Sie dieses Privileg. Stattdessen erklärt dieses Dokument das Design in einer Form, die Sie überprüfen können.

Für wen das ist

  • Ingenieure entscheiden über die Installation
  • Sicherheitsforscher und Journalisten, die vor einer Rezension oder einem Artikel die Interna verstehen wollen
  • Sicherheitspersonal bei Partnerunternehmen evaluiert einen internen Rollout oder eine OEM-Bündelung

Was dieses Dokument nicht abdeckt

Es geht nicht um die Optimierung der Erkennungsschwelle, falsch-positive Statistiken oder exemplarische Vorgehensweisen für die Benutzeroberfläche. Es erklärt vier Dinge: Privilegien, Prozessgrenzen, Datenfluss und Kryptographie. Die Funktionsspezifikationen selbst befinden sich in der gebündelten MCP-Ressource roamswitch://docs/features und in der In-App-Hilfe.

Was wird offengelegt und wie weit (Offenlegungsrichtlinie)

Dieses Dokument basiert auf der Annahme, dass ein Angreifer bereits über die verteilte Binärdatei verfügt. Alle Endpunkt-URLs, Kennungen, Dateipfade, XPC-Protokolle und eingebetteten öffentlichen Schlüssel, die hier angezeigt werden kann in wenigen Minuten aus dem Versand RoamSwitch.app gezogen werden strings, codesign -d oder ein Verkehrsproxy. Schreiben Sie sie daher hier auf gibt einem Angreifer nichts Neues. Der einzige Fortschritt ist das Verständnis des Rezensenten.

Andererseits ist die serverseitige Implementierung nicht aus der Binärdatei ersichtlich – Rate-Limit Schwellenwerte, Schlüssel, Admin-Endpunkte, das DB-Schema, das Firebase-Projektlayout – sind nicht enthalten. Das OEM- und Partner-Integrationsdesign liegt hier ebenfalls nicht im Rahmen und wird separat behandelt internes Dokument. „Was man durch die Beobachtung des Klienten lernen kann“ lautet die Offenlegungszeile hierfür Dokument.

Hinweis

Dieses Dokument entspricht der Quelle für die oben angegebene Version. Wo sich das Verhalten ändert In einer späteren Version wird das Dokument überarbeitet und die Versionsnummer und der Ziel-Build werden aktualisiert. Sollten Sie eine Diskrepanz zwischen dem Text und dem Code feststellen, teilen Sie uns dies bitte unter mit lafine.net/contact.html.

§2

RoamSwitch.app besteht aus drei ausführbaren Dateien. Nur einer von ihnen ist privilegiert; die Die anderen beiden werden mit Login-Benutzerrechten ausgeführt. Alle drei werden mit aktivierter Hardened Runtime und Entwickler-ID ausgeliefert unterzeichnet und notariell beglaubigt.

Diagramm der RoamSwitch-Komponenten und Vertrauensgrenzen MCP-Client Claude Desktop / Code MCPServer Benutzerrechte Nur lesend RoamSwitch.app Benutzerrechte Menüleiste / Überwachung / UI Helper root / LaunchDaemon SMAppService.daemon System-Binärdateien pfctl / socketfilterfw … stdio (JSON-RPC) Nur lesend * XPC mach service Autorisiert per Code-Signatur Prozessausführung
* MCPServer stellt keine Verbindung zur App selbst her; Es liest die gemeinsame Präferenzdomäne und die Überwachungsmodule direkt (§8).
Berechtigungen und Rolle jeder Komponente
AusführbarPrivilegKannGeht nicht
RoamSwitch
.app
Benutzer anmelden Überwachen Sie den Netzwerkstatus, führen Sie Diagnosen aus, zeichnen Sie die Benutzeroberfläche, rufen Sie den Helfer über XPC auf, ändern Sie AirDrop über defaults, starten Sie ClamAV (optional). Betreiben Sie die Firewall, PF oder System-Daemons direkt (alles läuft über den Helfer).
RoamSwitch
Helper
root Nur die in HelperProtocol (Tabelle §3) aufgeführten Vorgänge: Firewall/Stealth, Laden/Entladen der Sharing-Daemons, Anwenden des PF-Regelsatzes, DNS-Änderung, Senden von Signalen an Prozesse Noch etwas. Es gibt keine Schnittstelle zum Ausführen beliebiger Befehle. Es besteht auch keine Berechtigung zum Senden über das Netzwerk
RoamSwitch
MCPServer
Benutzer anmelden Diagnosewerte lesen und formatieren, lokale Wissensdatenbank durchsuchen; Die Ergebnisse werden über stdio an den Client zurückgegeben Ändern Sie Einstellungen, schalten Sie die Sperre um, isolieren Sie einen Port, werfen Sie ein Gerät aus. Es öffnet sich kein Socket. Es wird nichts über das Netzwerk gesendet

Berechtigungen und Unterzeichnung

  • Alle drei Ziele haben ENABLE_HARDENED_RUNTIME = true.
  • App Sandbox ist deaktiviert (com.apple.security.app-sandbox = false). Die Berechtigungen des Helfers und des MCPServers sind leere Wörterbücher.
  • Distributions-Builds werden vom Entwickler-ID-Antrag unterzeichnet, von Apple notariell beglaubigt und geheftet (§10).
Design-Kompromiss

App Sandbox wird nicht verwendet. RoamSwitch muss die Hardware-UUID von IOKit lesen, CoreWLAN verwenden und DiskArbitration, Listening-Sockets anderer Prozesse (lsof) auflisten, einen XPC öffnen Verbindung zu einem LaunchDaemon herstellen und Systembinärdateien erzeugen. Nichts davon ist im Inneren möglich Sandbox, daher bleibt sie deaktiviert.

Vier Dinge gleichen das aus. Erstens: Gehärtete Laufzeit. Zweitens: Signieren der Entwickler-ID und notarielle Beurkundung. Drittens wird nur eine ausführbare Datei als Root ausgeführt – der Helfer – und was dieser Helfer tun kann ist festgelegt und aufgezählt (Tabelle §3). Viertens werden Verbindungen zum Helfer durch Code eingeschränkt Unterschrift (§3).

§3

Wie es registriert wird

Der Helfer wird mit SMAppService.daemon(plistName:) als LaunchDaemon registriert. Die plist in die App eingebettet (Contents/Library/LaunchDaemons/com.tetsuharu.RoamSwitch.Helper.plist) deklariert nur Label, BundleProgram, ein einzelner MachServices-Eintrag und AssociatedBundleIdentifiers. Aufgrund der Funktionsweise von SMAppService Eine Registrierung ist nicht einmal möglich, es sei denn, die App ist in /Applications. Am ersten Nach der Registrierung wird der Helfer erst dann aktiv, wenn der Benutzer ihn im System manuell genehmigt Einstellungen.

Wessen Verbindungen es akzeptiert (ClientValidator)

Der Helfer überprüft den Verbindungsvorgang in NSXPCListeners shouldAcceptNewConnection und verteilt HelperProtocol nur an diejenigen, die passieren. Die Inspektion verwendet den audit_token anstelle der PID Vermeiden Sie die Wiederverwendung von PIDs und TOCTOU.

# Code-Signing-Anforderungen, die der Release-Build an verbindende Clients stellt
identifier "com.tetsuharu.RoamSwitch"
  and anchor apple generic
  and certificate leaf[subject.OU] = "GV76B6G4YU"

Diese Anforderung wird mit SecCodeCopyGuestWithAttributes und überprüft SecStaticCodeCheckValidity, und die Verbindung wird getrennt, wenn sie nicht erfolgreich ist. Nur DEBUG-Builds verzichten aus Gründen der Entwicklungsfreundlichkeit auf die Team-ID-PIN. Was tatsächlich versendet wird, ist immer ein Release-Build.

Grenzen im Überblick

Die Sicherheit des Helfers beruht auf dieser einzigen Codesignaturanforderung. Alles, was es erfüllt (a ordnungsgemäß signiert RoamSwitch.app) kann jede Operation in der folgenden Tabelle aufrufen. Es gibt Kein Kanal für die Eingabe beliebiger Befehle, aber die Operationen in dieser Tabelle weisen keine Schwachstellen auf sich selbst. Wenn RoamSwitch.app selbst übernommen wird, gehen diese Operationen an den über Angreifer.

Was der Helfer tun kann (die vollständige Liste)

Die in Shared/HelperProtocol.swift definierten privilegierten Operationen sind alle davon. Es gibt keine privilegierte API, die hier nicht aufgeführt ist.

HelperProtocol – alles, was als Root ausgeführt wird
MethodeWas es bewirktBinär/API aufgerufen
setBlockAll(_:) Schaltet die Anwendungs-Firewall und den Stealth-Modus ein oder aus /usr/libexec/ApplicationFirewall/socketfilterfw
--setblockall / --setstealthmode
getBlockAllStatus(...) Liest die aktuellen Werte der oben genannten socketfilterfw --getblockall
setSharingServicesEnabled(_:) Entladen/Laden der SSH-/SMB-/Screen-Sharing-Daemons. Beim Stoppen werden nur „die ausgeführten“ aufgezeichnet und nur diese wiederhergestellt /bin/launchctl list / unload -w / load -w
(festgelegt auf die drei: ssh.plist / com.apple.smbd.plist / com.apple.screensharing.plist)
enableNetworkAirGap(...)
disableNetworkAirGap(...)
Wendet die Not-Vollsperre (block drop all) an und hebt sie auf. Geht durch PFRulesetCoordinator (§4) /sbin/pfctl -f / -e / -sr
setGuardedDevServerPorts(_:) Verwendet pf, um nur external Verbindungen zu den angegebenen Dev-Server-Ports zu blockieren (localhost leitet durch). Durch das Übergeben eines leeren Arrays werden alle angehoben /sbin/pfctl (auch über den Koordinator)
setSecureDNSServers(_:)
restoreOriginalDNSServers(...)
getCurrentDNSServers(...)
Schaltet das DNS aktiver Netzwerkdienste auf Malware-blockierendes DNS (Quad9 9.9.9.9 / Cloudflare 1.1.1.2) um, sichert die ursprünglichen Einstellungen und stellt sie wieder her /usr/sbin/networksetup
-listallnetworkservices / -getdnsservers / -setdnsservers
setLinkGuardSinkhole(_:) Linkschutz (§5). Schreibt die angegebenen Phishing-/Betrugsdomänen in einen durch Trennzeichen getrennten verwalteten Abschnitt von /etc/hosts als 0.0.0.0 und leert dann den DNS-Cache. Ein leeres Array entfernt den Abschnitt. Domänen werden normalisiert und dedupliziert; IPs und Junk werden verworfen; auf 60.000 begrenzt; geschrieben über eine temporäre Datei + atomares Ersetzen schreibt /etc/hosts (FileManager.replaceItemAt)
/usr/bin/dscacheutil -flushcache
/usr/bin/killall -HUP mDNSResponder neu
lockGatewayARP(_:)
unlockGatewayARP(...)
getGatewayARPLockStatus(...)
Präventive Gateway-ARP/NDP-Sperre (§5). Pinnt die angegebenen IP → MAC-Zuordnungen (das IPv4-Gateway, den IPv6-Standardrouter, On-Link-DNS-Resolver) als permanent-Neighbour-Cache-Einträge. IP- und MAC-Formate werden validiert; ein Abgleichsmodell (Pins, die nicht in der Anfrage enthalten sind, werden entfernt). Der Pinsatz wird auf gateway_arp_lock.json beibehalten. /usr/sbin/arp -s / -d
/usr/sbin/ndp -s / -d
wireGuardImport(_:)
wireGuardForget(...)
VPN-Tunnel (§5). Der Helfer speichert/löscht den WireGuard .conf-Text bei 0600 Datei nur schreiben
wireGuardUp(endpointIPv4:endpointIPv6:port:)
wireGuardDown(...)
wireGuardStatus(...)
Bringen Sie den Tunnel nach oben/unten/lesen Sie den Status. Der Endpunkt-Hostname wird von der App aufgelöst und die IP wird an den Helfer übergeben (der DNS des Helfers kann durch den Kill-Switch unterbrochen werden). Homebrew wg-quick up/down, wg show (wireguard-tools; deaktiviert, wenn nicht installiert)
termineProcess(pid:forceKill:) Hält einen Prozess an (SIGSTOP) oder erzwingt das Beenden (SIGKILL). Wird verwendet, um Ransomware-ähnliche Prozesse einzudämmen. Nur pid > 1 kill(2)-Systemaufruf (kein Unterprozess)
getHelperVersion(...) Gibt die Versionszeichenfolge des Helfers zurück (wird für App-Kompatibilitätsprüfungen verwendet)
Design-Kompromiss

terminateProcess kann SIGKILL an jeden Prozess senden, solange pid > 1. setSecureDNSServers akzeptiert jede DNS-Serverzeichenfolge. Das ist die Breite, die das Feature benötigt, aber es ist nicht schmal. Beurteilen Sie es mit dem Verständnis, dass die Die Codesignaturprüfung davor (ClientValidator) ist das einzige Tor.

Zustand im Helfer

  • HelperTool.shared ist eine einzelne Instanz, die von allen Verbindungen gemeinsam genutzt wird. Früher war es eine separate Instanz pro Verbindung, sodass eine Notfalleindämmung, die eine neue Verbindung öffnete, zu einem Rennen führen konnte, bei dem der Überblick darüber verloren ging, „welche Dienste wiederhergestellt werden sollten“.
  • Der Sharing-Service und die DNS-Backups werden nur in einer seriellen Warteschlange (stateQueue) mutiert.

§4

Vier Funktionen berühren Pf: den Notfall-Air-Gap, den Dev-Server-Port-Guard und die VPN-Tunnel WireGuard-Kill-Switch (§5, 1.7.6+) und sein Tailscale-Kill-Switch (§5, 1.8.0+ – nur die ausgewählten Backends). Alle gehen immer über einen einzelnen Einstiegspunkt, PFRulesetCoordinator, und wird niemals ausgeführt pfctl -f selbst.

Warum es einen einzigen Einstiegspunkt gibt

Zuvor luden die beiden Funktionen jeweils unabhängig voneinander Regeln mit pfctl -f und konkurrierten über den einzigen Hauptregelsatz von pf. Wenn die enge Regel des Hafenwächters block ... port {…} war Nachdem der Luftspalt block drop all geladen wurde, könnte es zu einem Zustand kommen, in dem der Bildschirm nicht mehr funktioniert sagte „isoliert“, aber der Mac war immer noch erreichbar. Dieser Fehler wurde durch einen tatsächlichen Angriff auf gefunden Maschine von einem anderen Host und wurde in 1.4.3 behoben (die Geschichte ist geschrieben in docs/marketing/zenn/03_lan_side_attack_test.md).

Wie es jetzt funktioniert

  • Jedes Mal vollständig neu erstellt. Der gesamte erforderliche Regelsatz wird ausgehend vom aktuellen Status neu erstellt und auf einmal angewendet. Es wird niemals als Diff angewendet.
  • Eine serielle Warteschlange. Jede PF-Änderung wird auf demselben DispatchQueue ausgeführt. Unabhängig davon, ob sie von einer XPC-Verbindung, dem Start des Hilfsprogramms oder dem Failsafe-Timer stammt, werden Änderungen der Reihe nach verarbeitet.
  • Die Prioritätsreihenfolge ist wie folgt (weiter oben stehende Einträge haben Vorrang).
    1. Notluftspalt → set skip on lo0 und block drop all (nichts anderes wird berücksichtigt)
    2. VPN-Kill-Switch → block drop all plus pass quick nur für: lo, die Tunnelschnittstelle (utunN), den UDP-Handshake zu den angepinnten Endpunkt-IP(s), DHCP und ICMP
    3. Dev-Server-Wächter → block drop in quick proto tcp ... port { … }
    4. Keine → /etc/pf.conf neu laden und pf in seinen ursprünglichen Zustand zurückversetzen
  • Nach der Anwendung zurücklesen. pfctl -sr liest die Regeln zurück, um zu bestätigen, dass block drop all oder die Regel jedes Ports tatsächlich geladen ist. Ein Fall, in dem pfctl -f stillschweigend ignoriert wurde, wird nicht als Erfolg gewertet.
  • Die temporäre Datei wird in einen Pfad geschrieben, der einen UUID enthält, und nach der Anwendung gelöscht. (v1.4.5 hat den festen Pfad zugunsten eines schwer zu erratenden Pfads gelöscht). Das Statusverzeichnis ist /Library/Application Support/RoamSwitch.
API-Verhalten

Die XPC-Antworten von enableNetworkAirGap und setGuardedDevServerPorts, (Bool, String?), melden Sie, ob der Vorgang vollständig durchlaufen wurde zurücklesen. Der Aufrufer (z. B. ARPSpoofContainmentManager) versucht es bei einem Fehler erneut Wenn es immer noch fehlschlägt, wird die Meldung direkt auf dem Bildschirm angezeigt: „Der Verkehr wurde noch nicht gestoppt. Ausschalten.“ Jetzt WLAN.“

§5

Die Arten von Blöcken sind jeweils unterschiedlich

Arten von Blöcken
FreundlichUmfangAuslöserLoopback
Notluftspalt Stoppt den gesamten eingehenden und ausgehenden Datenverkehr Wenn Ransomware-ähnliche Verschlüsselungsaktivitäten erkannt werden. Bei ARP-Spoofing-Erkennung wird es nur im Lockdown sofort ausgelöst; Bei ausgeglichenen/vertrauenswürdigen Netzwerken wird stattdessen eine Benachrichtigung gesendet (Sie lösen es manuell aus). Bei einem bekannten „ClickFix“-artigen Befehlsmuster im Shell-Verlauf, etwa dem Base64-Dekodieren direkt in eine Shell oder AppleScript (1.8.7+, Pro, standardmäßig deaktiviert). Wird nicht für den alltäglichen Schutz unterwegs verwendet Durchgereicht mit set skip on lo0
VPN-Kill-Switch Alles außer dem Tunnel, seinem Handshake, DHCP und ICMP Wenn der VPN-Tunnel (§5, Pro, standardmäßig deaktiviert) aktiviert ist und Sie sich einem nicht vertrauenswürdigen Netzwerk anschließen. Wird gehalten, bis der Tunnel eingerichtet ist (und solange er geschlossen ist) Durchgereicht mit set skip on lo0
Dev-Server-Portwächter Nur external TCP-Verbindungen zu den angegebenen Ports Eine manuelle Isolierung mit einem Klick oder automatische Blockierung, wenn ein unbekannter Abhörport erkannt wird (Pro) Von localhost, unverändert
Täglicher Schutz vor nicht vertrauenswürdigen Netzwerken Firewall und Stealth, Freigabe gestoppt (§6). pf wird nicht verwendet Wenn Sie eine Verbindung zu einem Netzwerk herstellen, sind Sie nicht registriert
Linkschutz Nur Namensauflösung von Phishing-/Betrugsdomänen (0.0.0.0 über /etc/hosts). pf wird nicht verwendet Ein Ziel im Bedrohungs-Feed oder ein Markenhomograf. Standardmäßig aktiviert (Pro) Nicht betroffen
Präventive ARP/NDP-Sperre Nur der MAC des Gateways, des IPv6-Routers und On-Link-DNS (Nachbarcache). pf wird nicht verwendet Beim Beitritt zu einem nicht vertrauenswürdigen Netzwerk (Pro, standardmäßig deaktiviert). Wird bei jedem Netzwerkwechsel neu angepinnt Nicht betroffen

Wie verhindert wird, dass der Luftspalt bestehen bleibt

  • Sie wird nach spätestens 10 Minuten aufgehoben. Der Helfer selbst führt weiterhin unmittelbar nach dem Start und über einen 60-Sekunden-Timer releaseAirGapIfExpired() aus, aber als vollständig unabhängiges Sicherheitsnetz erwacht ein dedizierter LaunchDaemon (AirGapFailsafe) ohne jegliches KeepAlive selbstständig alle 3 Minuten und führt dieselbe Prüfung und Aufhebung durch. Stürzt der Helfer selbst ab und reißt seinen eigenen Selbstaufhebungs-Timer mit sich, bleibt dieses Sicherheitsnetz davon unberührt (ab 1.8.6).
  • Dieser dedizierte Daemon rührt niemals die eigene Startkonfiguration des interaktiven Helfers an. Ein früherer Ansatz (1.8.5) nutzte für diese Wiederherstellung das eigene KeepAlive.PathState des Helfers, das jedoch gelegentlich mit einem normalen Beenden der App kollidierte und einen unbeabsichtigten Neustart auslöste, weshalb er zugunsten des jetzigen, vollständig unabhängigen Daemons zurückgenommen wurde.
  • Die Zeitstempelprüfung verwendet eine Hybridlösung aus monotoner Systemlaufzeit (ProcessInfo.systemUptime) und der Uhrzeit. Bevorzugt wird normalerweise die monotone Systemlaufzeit, sodass NTP-Korrekturen und manuelle Uhrzeitänderungen keine Auswirkung haben. Nur wenn die Systemlaufzeit nicht vertrauenswürdig ist – unmittelbar nach einem Neustart, erkannt daran, dass der aktuelle Wert kleiner ist als der gespeicherte – wird auf die Uhrzeit zurückgegriffen.
  • Es wird nach einem Neustart oder einem Daemon-Respawn erneut angewendet. Beim Start liest der Helfer den Zustand auf der Festplatte mit reapplyFromDisk() und stellt ihn selbst wieder her, in der Reihenfolge Air Gap, Port Guard, Systemstandard (auch hier gilt die 10-Minuten-Regel).
  • ___ Auf dem Bildschirm wird nie fälschlicherweise „angehoben“ angezeigt.
  • Sie können jederzeit die Kontrolle zurückerlangen – mit der Lift-Taste im Modal oder einfach durch Ausschalten des WLANs.

Wie ein Port-Guard-Falsch-Positiv-Ergebnis wiederhergestellt wird

Die automatische Blockierung unbekannter Ports (Pro, standardmäßig aktiviert, sobald Pro aktiviert ist) kann einen legitimen Port stoppen LAN-Empfänger – LocalSend, Syncthing, alles, was nach der Aktivierung des Wächters gestartet wurde. Wenn das passiert, erlauben Sie es über die Schaltfläche „Zulassen“ im Benachrichtigungsbanner oder in der entsprechenden Zeile den Bildschirm „Freigelegte Anschlüsse“. Eine einmal zulässige ausführbare Datei wird als bekannt aufgezeichnet und nicht blockiert wieder (PortAnomalyGuard.allowPort(_:)). Beachten Sie, dass generische Skriptinterpreter (Python, Node.js, Netcat usw.) haben einen strengen Gültigkeitsbereich von path:port und nicht von Binärdateien allein, um Angriffe von Landbewohnern zu verhindern. Apple-System-Daemons, die zufriedenstellend sind anchor apple (rapportd, das Handoff unterstützt und dergleichen) sind es nicht als erstes gesehen.

Selbstheilender Ransomware-Kanarienköder und Eindämmungsunterdrückung

Wenn Canary-Decoy-Dateien manipuliert oder umbenannt werden und den Notfall-Luftspalt auslösen, erfolgt die Freigabe Nach der Sicherheitsüberprüfung werden fehlende oder beschädigte Canary-Dateien automatisch neu generiert kehren zu ihrem authentischen Basis-Hash zurück, der aus eingebetteten Vorlagen generiert wurde, wodurch die ununterbrochene Überwachung der K-Warteschlange sofort wiederhergestellt wird (wodurch eine Kontamination der Basislinie durch den Gegner verhindert wird). Darüber hinaus werden während der aktiven Eindämmung (während das Notfallmodal angezeigt wird) redundante Benachrichtigungen und erneut auslösende Ereignisse aus regelmäßigen Hintergrund-Integritätsabfragen automatisch unterdrückt, um eine Ablenkung des Benutzers während der Reaktion auf den Vorfall zu vermeiden.

Mehrschichtige Erkennung heruntergeladener Dateien (statische Signaturen + ClamAV) – statische Signaturschicht ab 1.8.7

Neu im Downloads-, Schreibtisch- oder Dokumente-Ordner abgelegte Dateien durchlaufen zunächst eine leichtgewichtige statische Signaturprüfung durch StaticSignatureScanner (nur die ersten 4 MB, einfacher AND/OR-Bytemuster-Abgleich – keine regulären Ausdrücke oder Entropieberechnungen). Sie benötigt kein EndpointSecurity-Entitlement und funktioniert auch dort weiter, wo ClamAV nicht installiert ist. Die Erkennung ist bewusst auf das beschränkt, was ohne einen echten Malware-Korpus als Tatsache belegt werden kann: die branchenübliche EICAR-Testsignatur sowie fünf in öffentlichen Offensive-Security-Referenzen (z. B. PayloadsAllTheThings) dokumentierte Lehrbuch-Reverse-Shell-Einzeiler – /dev/tcp/ von bash/sh, -e von netcat, pty.spawn von Python, Socket von Perl und fsockopen von PHP. Wir schreiben keine bytegenauen „Signaturen“ für namentlich bekannte Malware-Familien, ohne eine echte Probe zu besitzen, aus der sie extrahiert werden könnten – das wäre nur ein trügerisches Sicherheitsgefühl. Die Muster selbst werden XOR-0x5A-verschleiert gespeichert, damit RoamSwitchs eigene Binärdatei niemals eine wörtliche EICAR-Zeichenfolge oder einen Reverse-Shell-Einzeiler enthält, wegen der ClamAV selbst sie melden könnte.

Nur Dateien, die die statische Signaturschicht als „sauber“ einstuft, gehen weiter in den ClamAV-Scan. Neu im Downloads-, Schreibtisch- oder Dokumente-Ordner abgelegte Dateien werden unabhängig von einer .tmp-Erweiterung oder einem com.apple.quarantine-Attribut (etwa bei einer über das Terminal erstellten Kopie) sofort von ClamAV gescannt. EICAR und andere branchenübliche Testsignaturen gelten als harmlos: Es wird keine Benachrichtigung angezeigt, sondern nur ein Eintrag im Benachrichtigungsverlauf angelegt – und sie werden nie unter Quarantäne gestellt oder blockiert (nur echte Malware-Proben werden unter Quarantäne gestellt). Und war bereits zuvor eine Datei gleichen Namens unter Quarantäne gestellt worden, wird die neue trotzdem unter einem eindeutigen, zeitgestempelten Namen in den Quarantäne-Ordner verschoben, sodass eine Bedrohung wegen einer Namenskollision nie an ihrem ursprünglichen Ort verbleiben kann.

Überwachung neuer Autostart-Persistenz (LaunchAgent/LaunchDaemon) – 1.8.7

Neue .plist-Dateien unter ~/Library/LaunchAgents, /Library/LaunchAgents oder /Library/LaunchDaemons werden per FSEvents in Echtzeit erkannt (PersistenceMonitorGuard). Ohne ES_EVENT_TYPE_AUTH_CREATE von EndpointSecurity lässt sich der Schreibvorgang selbst nicht blockieren. Möglich ist jedoch, ihn innerhalb von Sekunden zu bemerken und den Inhalt zu bewerten.

Die Bewertung stützt sich darauf, was direkt gestartet wird, nicht auf die Signatur der ausführbaren Datei selbst. Reale Techniken aus dem Jahr 2026 – ein als Google Update getarnter LaunchAgent, der ein Base64-dekodiertes Bash-Skript verbirgt, oder ein LaunchDaemon mit Root-Rechten, der bei jedem Neustart eine Base64-dekodierte AppleScript-Payload erneut ausführt – verstecken den bösartigen Code beide Male im Skript selbst, während sie ein gültig signiertes /bin/bash oder /usr/bin/osascript unverändert aufrufen. Eine Prüfung, die nur die Signatur der ausführbaren Datei betrachtet, würde beides ungehindert durchlassen. Deshalb wird jeder neu registrierte LaunchAgent/LaunchDaemon, der einen rohen Skriptinterpreter (bash, sh, zsh, osascript, python3, perl, ruby, php und Ähnliches) direkt aufruft, unabhängig von dessen gültiger eigener Signatur, ausnahmslos gemeldet. Die dabei übergebenen Argumente werden zudem durch StaticSignatureScanner geprüft, und jedes gefundene bekannte bösartige Muster wird in die Benachrichtigung aufgenommen. Einträge, die über BundleProgram (verweist auf eine signierte, kompilierte Binärdatei innerhalb eines App-Bundles – einschließlich RoamSwitchs eigenem Helfer) registriert wurden, werden ganz normal per codesign --verify --strict verifiziert.

ClickFix-Erkennung und Notfall-Abriegelung – 1.8.7, standardmäßig deaktiviert

„ClickFix“ ist eine Social-Engineering-Technik, bei der ein gefälschtes CAPTCHA oder eine Fehlermeldung dazu auffordert, das Terminal zu öffnen und einen Befehl „zur Verifizierung“ einzufügen. Die Erkennungen stiegen von 2024 bis 2025 um über 500 %, und bis 2026 gilt sie als einer der am weitesten verbreiteten macOS-Angriffsvektoren. Da es sich um die eigene, legitime Shell handelt, die genau das ausführt, was eingegeben wurde, umgeht sie Gatekeepers Signaturprüfung vollständig.

Menüleiste → Malware-Schutz → ClickFix-Abwehr (Pro, standardmäßig deaktiviert). Überwacht per FSEvents neu angehängte Zeilen in ~/.zsh_history/~/.bash_history (nur Zeilen, die nach dem Start der Wache hinzugefügt werden – der bestehende Verlauf wird nie durchsucht) und gleicht ausschließlich die Reverse-Shell-Einzeiler ab, die sie mit StaticSignatureScanner teilt, sowie die spezifische Kombination aus Base64-Dekodierung direkt in eine Shell oder in osascript. Ein bloßes curl | bash – bei legitimen Installationsprogrammen äußerst verbreitet – ist bewusst ausgeschlossen, da es sich nicht von den offiziellen Installationsanleitungen für Homebrew, rustup, nvm und Ähnliches unterscheiden lässt. Sobald eine Übereinstimmung gefunden wird, löst sie denselben oben beschriebenen Notfall-Air-Gap aus. Da der Befehl bereits ausgeführt wurde, geschieht dies zwangsläufig im Nachhinein, kann aber dennoch einen laufenden zweiten Download oder eine Zugangsdaten-Exfiltration unterbrechen. Wie jeder andere Air-Gap-Auslöser hebt sie sich von selbst nach spätestens 10 Minuten auf (siehe Beginn dieses Abschnitts).

Eine bekannte Einschränkung. Da die Erkennung von einem Schreibvorgang in den Shell-Verlauf abhängt, kann sie die dateilose Variante nicht erfassen, die das Terminal vollständig umgeht, indem sie den Skripteditor direkt über das applescript://-URL-Schema aufruft und nichts auf die Festplatte schreibt. Apple hat hierfür eine gewisse Abschwächung eingeführt (ein Bestätigungsdialog für nicht identifizierte Skripte), doch es wurden Varianten gemeldet, die diese umgehen. Wir haben diesen Pfad auf echter Hardware gegen das einheitliche macOS-Protokoll (log show/log stream) getestet und kein charakteristisches Protokollsignal gefunden, an dem eine Erkennung ansetzen könnte. Wir stellen diese Einschränkung lieber offen dar, als eine Abdeckung zu behaupten, die wir nicht haben.

Docker-Risikoerkennung — 1.8.9, Pro, standardmäßig deaktiviert

Menüleiste → „Malware-Schutz“ → „Privilegierte Docker-Container & docker.sock-Mounts erkennen“ (DockerEventGuard). Da es in dieser Codebasis keinen Präzedenzfall für eine dauerhafte Streaming-Verbindung wie docker events gibt, wird derselbe Timer-Polling-Ansatz wie bei PortAnomalyGuard verwendet. Alle 20 Sekunden wird mit einem leichten docker ps -q die Menge der Container-IDs abgerufen, und nur die Differenz zum vorherigen Stand (neu gestartete Container) wird mit docker inspect --format im Detail geprüft. Der zur Erkennung verwendete Format-String ist absichtlich identisch mit dem der Linux-Edition (roamswitch_core::health::LinuxHealthChecker::DOCKER_INSPECT_RISK_FORMAT), sodass beide Plattformen exakt dieselben Bedingungen erkennen (Start im --privileged-Modus oder ein /var/run/docker.sock-Bind-Mount).

Bei der Erkennung wird keine automatische Aktion ausgelöst. Ein privilegierter Container oder ein docker.sock-Mount ist eine riskante „Konfiguration“, die einen Container-Escape ermöglichen könnte, aber keine bestätigte Kompromittierung – es gibt auch legitime Anwendungsfälle, etwa den bewussten Betrieb eines Überwachungs-Agents als privilegiert. Da die meisten Nutzer überhaupt kein Docker verwenden, bleibt diese Funktion auch mit Pro-Lizenz standardmäßig deaktiviert. Sie verwendet nicht das EndpointSecurity-Entitlement; die docker-CLI wird zunächst am Standard-Installationspfad von Docker Desktop, dann über Homebrew und schließlich über which gesucht. Verifiziert an einer echten Docker-Desktop-Installation (29.7.2) anhand von drei Szenarien – ein privilegierter Container, ein Container mit docker.sock-Mount und ein normaler Container – ohne Fehlalarme oder verpasste Erkennungen.

Geheimnis-/API-Schlüssel-Leck-Audit — hinzugefügt in 1.8.4, Ordner-Scan hinzugefügt in 1.8.9

Menüleiste → „Malware-Schutz“ → „Geheimnis-/API-Schlüssel-Leck-Audit“. Text einfügen, und er wird sofort auf durchgesickerte API-Schlüssel und Tokens geprüft, mit Zeilennummer, maskiertem String und einer Handlungsempfehlung je Fund (SecretLeakAuditor, vollständig auf dem Gerät). In 1.8.9 kam die Option „Ordner zum Scannen auswählen“ hinzu, mit der dieselbe Erkennungs-Engine ein Verzeichnis – etwa einen Quellcode-Checkout – rekursiv über auditDirectory(at:) prüfen kann. .git, node_modules, target, vendor, dist, build, __pycache__ und venv werden automatisch ausgeschlossen, ebenso Dateien über 2 MB oder als Binärdatei erkannte Dateien. Die Verarbeitung läuft außerhalb des Hauptthreads, um die Oberfläche nicht zu blockieren, und es wird niemals etwas nach außen gesendet.

Link Guard (blockiert Phishing-Verbindungen) – 1.7.2 und höher, verstärkt in 1.8.0

Menüleiste → „Malware-Schutz“ → „Link Guard“ (Pro). Blockiert Verbindungen zu Phishing-/Betrugsseiten auf dem Gerät, in jedem Browser und in jeder App. Es gibt zwei Durchsetzungspunkte, die zusammen in der Reihenfolge ihrer Priorität verwendet werden.

  • ① Content-Filter-Systemerweiterung (RoamSwitchLinkFilter, 1.8.0+, nach Genehmigung bevorzugt). Eine NEFilterDataProvider-Systemerweiterung – keine Apple-Überprüfung (Content-Filter-Anbieter sind Selbstbedienungsanbieter, keine Genehmigungswarteschlange). Es überprüft den tatsächlichen ausgehenden TCP-Fluss after Namensauflösung. Der Zielname stammt aus dem vom Betriebssystem aufgelösten Hostnamen oder, falls dies nicht der Fall ist, wurde der TLS SNI aus den ersten Bytes des Flusses geparst – ein Browser, der sein eigenes DoH/DoT ausführt und eine Verbindung zu einer nackten IP herstellt, wird also immer noch blockiert. Es schreibt /etc/hosts nie neu und ordnet jeden Fluss einem Prozess zu. QUIC (UDP/443) hat kein lesbares SNI, daher wird es im block-Modus gelöscht, wodurch der Browser gezwungen wird, auf HTTP/2 über TCP zurückzugreifen. Erfordert eine einmalige Genehmigung in den Systemeinstellungen.
  • /etc/hosts Sinkhole (Fallback, während die Erweiterung nicht genehmigt/abgelehnt ist). Der privilegierte Helfer schreibt die Zieldomänen in einen durch Trennzeichen getrennten verwalteten Abschnitt von /etc/hosts als 0.0.0.0 und leert den Cache. Maximal 60.000. Sobald die Erweiterung aktiv ist, wird dieser Abschnitt entfernt.
  • Drei Modi. „Aus“ deaktiviert es. „Nur warnen“ pausiert die passende Verbindung und fragt den Benutzer (siehe Real warn unten). „Offensichtliche Betrugsseiten automatisch blockieren (empfohlen)“ wird sofort entfernt. Der Standardwert ist Block ab 1.7.2.
  • ___ Sobald das Tippen des Benutzers allowlist.txt / extra.txt erreicht – die Erweiterung fragt alle 1,5 s die kleinen Statusdateien ab – werden die angehaltenen Flows fortgesetzt (zulassen) oder gelöscht (blockieren). Keine Antwort innerhalb von 25 s schlägt open fehl (eine Warnung ist beratend). Die Entscheidung wird pro Host zwischengespeichert (5 Minuten zulassen/1 Stunde blockieren), sodass die anderen Flüsse der Seite und spätere Besuche sofort erfolgen und erzwungen werden. Die block-Benachrichtigung ist unverändert: „Blockiert …“ mit der Schaltfläche „Einmal zulassen (5 Min.)“.
  • Nur eindeutige Fälle werden blockiert. Eine Auflistung im Bedrohungs-Feed oder ein Marken-Unicode-Homograph – alles andere (Hochrisiko-TLDs, Subdomain-Nachahmung usw.) ist eine Warnung. Die Urteils-Engine wird mit der Linux-Edition geteilt und sendet URLs nirgendwohin.
  • Wiederherstellung nach einer falschen Blockierung. Eine Domain über die Benachrichtigung oder das Menü zulassen (5 Minuten oder dauerhaft). Die Zulassungsliste wird abgezogen, wenn der Abschnitt neu generiert wird.
  • Pro-gated. Die Durchsetzung (applyMode()) erfolgt nur bei einer gültigen Pro-Lizenz. Ohne Pro wird der Modus gespeichert, aber /etc/hosts wird nie berührt. Die Aktivierung oder das Erlöschen einer Lizenz wird mitten in der Sitzung wirksam.
  • Feed und gebündelter Seed. Die Blockliste stammt aus dem signierten Bedrohungs-Feed (§7, verifiziert mit einem Feed-spezifischen Schlüssel). Es funktioniert bereits vor dem ersten Abruf mit dem gebündelten Seed der App (ca. 60.000 Einträge) und die Deaktivierung von „Auto-Update“ bedeutet, dass kein ausgehender Datenverkehr stattfindet.

Präventive Gateway-ARP/NDP-Sperre – 1.7.5 und höher

Menüleiste → „Port- und Gerätemonitor“ → „ARP/NDP des Gateways an nicht vertrauenswürdige Netzwerke anheften (präventiv)“ (Pro, standardmäßig deaktiviert).

  • Wie es funktioniert. Beim Beitritt zu einem nicht vertrauenswürdigen Netzwerk wird der aktuelle MAC des IPv4-Gateways, des IPv6-Standardrouters und der On-Link-DNS-Resolver von route / scutil --dns / arp -n / ndp -an erfasst, und der Helfer pinnt jeden als permanent-Eintrag mit arp -s / ndp -s (Vertrauen bei der ersten Verwendung – der erste beobachtete MAC ist vertrauenswürdig). Gefälschte ARP/NDP-Antworten für diese IPs werden dann ignoriert, sodass kein Man-in-the-Middle-Angriff durchgeführt werden kann.
  • Scope. Nur diese drei Arten von Einträgen werden angeheftet. Vertrauenswürdige (offene) Netzwerke werden niemals gepinnt. Bei jedem Netzwerkwechsel wird es einmal entsperrt und erneut angepinnt. Öffentliche Off-Link-Resolver (8.8.8.8, …) haben keinen On-Link-ARP-Eintrag und werden automatisch ausgeschlossen.
  • arp -s ist präventiv; der Luftspalt ist nachträglich. Dieser Pin existiert, daher kann eine Parodie nicht erfolgreich sein; Die ARP-Spoofing-Erkennung (ARPSpoofContainmentManager) und der Notfall-Luftspalt dienen dazu, „schneller als ein Mensch zu schneiden“, sobald einer erkannt wird. Sie laufen unabhängig.
  • Persistence. Der Pin-Satz wird unter /Library/Application Support/RoamSwitch/gateway_arp_lock.json gespeichert, sodass er bei einer erneuten XPC-Verbindung oder einem Neustart des Hilfsprogramms entsperrt werden kann.

Der VPN-Tunnel (WireGuard / Tailscale) und sein Kill-Switch – 1.7.6 und höher, auswählbares Backend in 1.8.0

Menüleiste → „Port- und Gerätemonitor“ → „VPN-Tunnel“ (Pro, standardmäßig deaktiviert). Dies ist die primäre Anti-MITM-Abwehr – sie hängt nicht von der Integrität von L2 (ARP/NDP) ab. Das Backend ist wählbar (Untermenü → „Backend“) zwischen „WireGuard (config file)“ und „Tailscale (Exit Node)“. RoamSwitch implementiert selbst keine Kryptografie; Nur das ausgewählte Backend ist scharfgeschaltet.

  • (A) WireGuard-Backend. Steuert Homebrews wireguard-tools (keine Berechtigung zur Apple Network Extension). Importieren Sie Ihr eigenes .conf; Der Helfer speichert es bei 0600. Kill-Switch: pf block drop all plus ein pass quick nur für lo, die Tunnelschnittstelle, den UDP-Handshake zu den angehefteten Endpunkt-IP(s), DHCP und ICMP. Ein nicht vollständiger Tunnel AllowedIPs löst eine Split-Tunnel-Warnung aus.
  • (B) Tailscale-Backend (1.8.0+). Für Benutzer, die Tailscale bereits ausführen. RoamSwitch führt nicht aus, führt tailscale up aus / meldet sich an / installiert es – es liest tailscale status --json und führt tailscale set --exit-node=<node> aus. Die eigenständige CLI (brew install tailscale) wird empfohlen – der App Store (GUI)-Build kann nicht von außerhalb der App (Sandbox) gesteuert werden; Damit wählen Sie den Ausgangsknoten in der Tailscale-App aus und RoamSwitch zeigt nur den Status an. Ein Ausgangsknoten ist erforderlich (leitet den gesamten Datenverkehr durch den Tunnel); Es wird automatisch deaktiviert, wenn es offline geht oder nicht erreichbar ist.
  • ___ Der Datenverkehr sinkt für ca. 5–10 s und die Schutzstufe wird in diesem Fenster nicht herabgestuft.
  • Der Tailscale-Kill-Switch ist standardmäßig deaktiviert (Opt-in). Der Exit-Knoten tunnelt bereits alles; der pf block drop all (erlaubt nur CGNAT/MagicDNS/STUN/DERP/DHCP/ICMP/DNS) ist für fortgeschrittene Benutzer und ist „lecksicher, nicht lecksicher“ (DNS ist erlaubt, daher bleibt tailscaled bestehen).
  • Automatisch / bei Lizenzverlust. Kommt bei nicht vertrauenswürdigen Netzwerken hoch, bei vertrauenswürdigen herunter; wird aufgehoben, wenn die Pro-Lizenz erlischt.

§6

Wenn Sie eine Verbindung zu einem Netzwerk herstellen, das Sie nicht registriert haben, wird der Schalter „Schutzstufe“ nicht verwendet pf. Es ändert lediglich die Standardeinstellungen des Betriebssystems auf eine Weise, die später rückgängig gemacht werden kann.

Operationen pro Schutzstufe
BetriebUmsetzungPrivilegWie es wiederhergestellt wird
Firewall + Stealth-Modus EIN socketfilterfw --setblockall on / --setstealthmode on root (Helfer) off, wenn Sie zu einem sicheren Netzwerk zurückkehren
Stoppen Sie SSH/SMB/Bildschirmfreigabe launchctl unload -w root (Helfer) Zeichnet nur diejenigen auf, die ausgeführt wurden, als sie gestoppt wurden, und load -w bei der Rückkehr (mit SSH auch gekoppelt an /usr/sbin/systemsetup -setremotelogin on für garantierte moderne macOS-Wiederherstellung)
Deaktivieren Sie AirDrop Standardmäßig wird com.apple.sharingd DiscoverableMode geschrieben Benutzer (die App selbst) Speichert den vorherigen Wert und schreibt ihn bei Rückkehr zurück

Dabei handelt es sich nicht um einen neuen Blockierungsmechanismus, den RoamSwitch hinzufügt – es handelt sich lediglich um das Umschalten der Betriebssystemeinstellungen. Wenn löscht man die App, stoppt nur noch die netzwerkabhängige Umschaltung; das letzte Betriebssystem Die angewendeten Einstellungen bleiben unverändert. Nichts bleibt gesperrt, aber wenn Sie sich irren möchten Stellen Sie es auf der sicheren Seite in einem vertrauenswürdigen Netzwerk wieder auf „Offen“, bevor Sie es deinstallieren.

§7

Was bleibt auf dem Mac

Auf der Festplatte gespeicherte Daten
DatenStandortInhalt
LizenztokenSchlüsselbund
com.tetsuharu.RoamSwitch.license
Ein Ed25519-signiertes Token. kSecAttrAccessibleAfterFirstUnlock
App-Einstellungen / Schutz ein-ausUserDefaults suite
com.tetsuharu.RoamSwitch
Registrierungen vertrauenswürdiger Netzwerke, Schutzrichtlinien, Ausschlusslisten usw
PF-Zustand/Library/Application Support/RoamSwitch/Der Air-Gap-Zeitstempel, JSON der geschützten Ports, der VPN-Kill-Switch-Status, die temporäre Datei für den angewendeten Regelsatz
Link Guard-Bedrohungsfeed~/Library/Application Support/RoamSwitch/threatfeed/feed.txtDie heruntergeladene Phishing-/Betrugsdomänenliste (oder der gebündelte Seed der App, falls noch nicht abgerufen). Die Feed-Version befindet sich in UserDefaults
Von Link Guard verwalteter Abschnitt/etc/hostsEin durch # BEGIN RoamSwitch link guard# END begrenzter, abgegrenzter Abschnitt, der blockierte Domänen auf 0.0.0.0 auf Null setzt. Wird entfernt, wenn der Modus „Aus“ ist (§5)
ARP/NDP-Sicherungsstifte/Library/Application Support/RoamSwitch/gateway_arp_lock.jsonDer IP → MAC-Satz wurde durch die präventive Sperre (§5) zu permanent gemacht. Beim Entsperren gelöscht
WireGuard-Konfiguration/Library/Application Support/RoamSwitch/ (Hilfsbereich, 0600)Der .conf, den der Benutzer importiert hat. Der Endpunkt-Hostname wird auch in UserDefaults gespeichert (die App löst ihn auf).
Geräte-Fallback-UUIDBenutzerstandardsEin Zufallswert, der nur generiert wird, wenn IOKit keine UUID zurückgibt (§9)
Protokolleos.Logger / NSLogEinheitliche Protokollierung. Es wird nichts nach außen gesendet

Verkehr, der die Maschine verlässt (die vollständige Liste)

Es gibt nirgendwo einen Code, der Diagnoseergebnisse, Portinformationen, URLs usw. sammelt und sendet Protokolle. Es sind kein Analyse-SDK und kein Crash-Reporter-SDK enthalten. Die einzige externe Bibliothek ist Sparkle (Updates). Was an das Netzwerk gesendet wird, sind diese acht, und das ist alles (die sechste nur, wenn der Benutzer ein VPN konfiguriert, die siebte nur, wenn die RoamSwitch Sensor-Kopplung aktiviert ist).

Ausgehende Verbindungen stellt RoamSwitch her
VerbindungZielWenn es passiertWas wird gesendet?
Lizenzaktivierung/-deaktivierung lafine.net
/api/v1/license/*
Nur wenn der Benutzer einen Lizenzschlüssel eingibt oder Pro deaktiviert Lizenzschlüssel, Geräte-Hash, Hostname, App-Version. Persönliche Daten werden beim Kauf von Stripe verarbeitet. Die App kommt damit nicht zurecht
Update-Prüfung lafine.net
/updates/appcast.xml
Sparkle, alle 24 Stunden und beim Start Eine HTTP-Anfrage (ein Standard-UA und eine Standardversion). Das heruntergeladene Element wird durch die EdDSA-Signatur überprüft (§10).
Link Guard-Bedrohungsfeed lafine.net
/updates/v1/{manifest, feed/.txt}
Wenn Link Guard (§5) aktiviert und „Auto-Update“ aktiviert ist, alle 24 Stunden (und beim Start). Wenn Sie „Automatische Aktualisierung“ deaktivieren, wird dieser Pfad entfernt Nur ein GET. Keine Abfragezeichenfolge, keine Cookies, nichts, was die Maschine identifiziert. Eine receive-only signierte statische Datei; Das Manifest und der Feedtext werden beide mit Ed25519 verifiziert. Der Signaturschlüssel ist dem Feed gewidmet – ein separater Schlüssel vom App-Update SUPublicEDKey (ein Leck ist also auf „eine fehlerhafte Sperrliste“ beschränkt).
Aktualisierungsdaten für Paket-CVE-Abgleich / aktive Schwachstellenprüfung lafine.net
/updates/v1/manifest
Alle 24 Stunden ab dem App-Start (immer — für die Aktualisierungsdaten des Paket-CVE-Abgleichs gibt es keinen Ausschalter, da es sich um rein empfangene Daten handelt, die nur für einen lokalen Listenabgleich verwendet werden; die CVE-Map der aktiven Schwachstellenprüfung wird nur abgerufen, wenn „Aktive Schwachstellenprüfung (aktive Erreichbarkeitsprüfung)“ aktiviert ist) Nur ein GET. Keine Query-String, keine Cookies, nichts, was das Gerät identifiziert. Eine nur empfangene, signierte statische Datei; Manifest und Feed-Inhalt werden beide mit Ed25519 verifiziert. Verwendet denselben Schlüssel und dasselbe Manifest wie der Link-Guard-Bedrohungsfeed, aber die tatsächlich abgerufenen Feeds selbst (bekannte CVE-Maps für Homebrew/npm/PyPI/crates.io/RubyGems/Packagist/Go/Maven, die CVE-Map der aktiven Schwachstellenprüfung sowie die Liste beliebter npm-Paketnamen für die Typosquatting-Erkennung) sind separate Dateien
Aktualisierung der ClamAV-Virendefinition Offizielle ClamAV-Spiegel Nur wenn der Benutzer ClamAV installiert hat und die Scanfunktion verwendet. Es startet freshclam Ein standardmäßiger ClamAV-Definitionsabruf. Es enthält keine von RoamSwitch abgeleiteten Informationen
VPN-Tunnel (§5, WireGuard / Tailscale) Der vom Benutzer konfigurierte WireGuard-Endpunkt oder die Tailscale-Kontrollebene (Tailscale, Inc.) Nur wenn der Benutzer den VPN-Tunnel eingerichtet hat (Pro, standardmäßig deaktiviert) und sich einem nicht vertrauenswürdigen Netzwerk anschließt. Bei WireGuard wird der Endpunkt-Hostname einmal über DNS aufgelöst, bevor der Tunnel aufgebaut wird. Bei Tailscale handelt es sich um Kontrollebenen-Datenverkehr, der von der bereits vom Benutzer installierten und angemeldeten tailscaled-Instanz abgewickelt wird — RoamSwitch selbst liest nur tailscale status --json und führt tailscale set --exit-node= aus Bei WireGuard: der WireGuard-Handshake (UDP) und der Verkehr im Tunnel. Das Ziel ist der eigene VPN-Server des Benutzers, der Inhalt ist der eigene Datenverkehr des Benutzers. Bei Tailscale: Datenverkehr zwischen dem eigenen Tailscale-Konto des Benutzers und der Kontrollebene von Tailscale, Inc. (Geräteregistrierung, DERP-Relay usw., gemäß der eigenen Datenschutzrichtlinie von Tailscale). In beiden Fällen fügt RoamSwitch keine Kennung und keine Diagnosedaten hinzu
RoamSwitch Sensor-Kopplung & Audit-Verbindung RoamSwitch Sensor im selben LAN (vom Benutzer selbst eingerichtete Hardware, die unter einer festen IP läuft) Nur wenn „RoamSwitch Sensor-Kopplung“ (Pro, standardmäßig deaktiviert) aktiviert ist und Sie die IP-Adresse und den Pairing-Code des Sensors zum Pairen eingeben (ein einmaliger Austausch). Nach dem Pairing verbindet es sich erneut mit derselben festen IP nur, wenn Sie „Audit von Sensor anfordern“ drücken, sowie beim automatischen Ergebnisabruf (beginnend 5 Minuten nach der Anfrage, danach alle 5 Minuten, bis zu 5 Versuche) Beim Pairing werden Hostname und Ed25519-Public-Key dieses Endpunkts gesendet, und der von Sensor ausgestellte Public Key wird empfangen. Audit-Anfragen und Ergebnisabruf werden mit einer Ed25519-Signatur authentifiziert — gesendet werden nur signierte Anfragen. Diagnoseergebnisse und Portinformationen werden ausschließlich als Antwort von Sensor empfangen; Dateiinhalte werden nie gesendet. Einziges Ziel ist die feste IP-Adresse des vom Benutzer selbst eingerichteten Sensors — sie erreicht nie einen externen Server, auch nicht lafine.net. Gegenseitiges Vertrauen entsteht ausschließlich durch den expliziten Austausch des Pairing-Codes
Checkout-Seite Streifenkasse Nur wenn der Benutzer den Kaufen-Button drückt (er öffnet sich im Browser) — (eine Browsernavigation)
Umfang von „Zero Telemetry“

„Zero Telemetry“ bedeutet hier, dass es keine Telemetrie gibt, die Nutzungsdaten sammelt und versendet bzw Diagnoseergebnisse. Das bedeutet nicht, dass überhaupt kein Netzwerkverkehr stattfindet. Die acht Wege im Die obige Tabelle existiert. Aber jeder von ihnen ist entweder etwas, das der Benutzer initiiert, oder ein signaturverifiziert, receive-only Abruf und die Diagnoseergebnisse, Ports, URLs, und Dateiinhalte auf dem Mac verlassen ihn nie.

Der Link Guard-Bedrohungsfeed (Zeile 3) fügt zusätzlich zu „Es sendet nichts“ hinzu: „Es ruft Updates ab“. Verteidigung. Die beiden werden getrennt gehalten; Das Linux-Whitepaper §1.1 spaltet ebenfalls „Zero Telemetrie“ von „Nur Updates empfangen“. Schalten Sie „Auto-Update“ aus und Link Guard wird auf dem Paket ausgeführt Daten (ca. 60.000 Phishing-/Betrugsdomänen) plus Offline-Homograph-Erkennung, und dieser Pfad tritt nicht auf.

Der VPN-Tunnel (Zeile 6) tritt nur auf, wenn der Benutzer seinen eigenen WireGuard-Server konfiguriert oder das Tailscale-Backend wählt und bereits mit seinem eigenen Tailscale-Konto bei tailscaled angemeldet ist; Ziel und Inhalt unterliegen der Kontrolle des Benutzers. RoamSwitch baut lediglich den Tunnel auf, hält den Kill-Switch oder liest den Tailscale-Status aus, um den Exit-Node zu wechseln — es fügt keine Kennung und keine Nutzungsdaten hinzu. Ohne konfiguriertes VPN existiert dieser Pfad nicht.

Die RoamSwitch Sensor-Kopplung (Zeile 7) ist eine reine Pro-Funktion, die standardmäßig deaktiviert ist; dieser Pfad existiert nicht, solange Sie ihn nicht aktivieren. Das Pairing selbst entsteht nur durch eine explizite Aktion — die Eingabe des vom Sensor-Betreiber ausgestellten Pairing-Codes zusammen mit der festen IP-Adresse des Sensors. Jede weitere Kommunikation (Audit-Anfragen, Ergebnisabruf) geht ebenfalls an dieselbe, dem Benutzer gehörende feste IP und wird mit einer Ed25519-Signatur authentifiziert. Sie erreicht nie einen externen Server, auch nicht lafine.net. Diagnoseergebnisse oder Dateiinhalte werden nie gesendet, außer als Antwort von Sensor selbst.

Das In-App-Blatt „Link-Sicherheitsprüfung“ sendet eine HEAD-Anfrage an die Ziel-URL, um sie anzuzeigen wo eine verkürzte URL landet (folgende Weiterleitungen zu privaten oder lokalen Adressen werden durch die gestoppt v1.4.5 SSRF-Abschwächung). Beim MCP audit_url_safety handelt es sich dagegen um eine Offline-Analyse Das wird sofort abgeschlossen und sendet die URL nirgendwo hin (§8).

Gemessen (2026-08-29) — Ergebnis: PASS

Dies wird nicht nur behauptet. Am 29.08.2026 wurde eine laufende 1.4.7-Installation mit geprüft tcpdump + Zuordnung pro Prozess (nettop / lsof / a gefiltert pktap Erfassung) + LuLu, über einen Zeitraum von ca. 2 Stunden, mit festgelegter Sicherheitsstufe Maximaler Lockdown und die Appcast-Prüfung erzwungen. Ergebnis: Kein ausgehender Fluss zugeordnet zu RoamSwitch, RoamSwitchHelper, oder RoamSwitchMCPServer außer der Appcast-Prüfung an lafine.net; der MCP Die einzigen Sockets des Servers waren zu localhost; Die Berechtigungs-Dumps sind leer.

Vollständige Beschreibung und ein Skript, das jeder ausführen kann, um es zu reproduzieren: audit/RESULTS-2026-08-29.md

Diese Messung stammt aus 1.4.7, vor dem Link Guard-Bedrohungsfeed (1.7.2, Zeile 3) und dem VPN Tunnel (1.7.6, Reihe 5). Bei der Prüfung ab Version 1.7.2 wird two „receive-only“ angezeigt GETs bis lafine.net (der Appcast und der Bedrohungs-Feed); wenn ein VPN konfiguriert ist, sehen Sie auch UDP zum eigenen WireGuard-Server des Benutzers (Ziel und Inhalt). unter der Kontrolle des Benutzers). Wenn „Auto-Update: Aus“ aktiviert ist und kein VPN konfiguriert ist, verschwindet alles.

§8

RoamSwitchMCPServer ist ein eigenständiges Befehlszeilentool, das unter gebündelt ist RoamSwitch.app/Contents/MacOS/. Ein MCP-Client wie Claude Desktop oder Claude Code startet ihn als Unterprozess und kommuniziert mit ihm über stdio (durch Zeilenumbrüche getrennter JSON-RPC). 2.0). Das offizielle SDK lässt sich nicht auf dem macOS SDK dieser Maschine aufbauen, ist also so von Hand auf Foundations JSONSerialization implementiert.

Was das Design einschränkt

  • Es ist schreibgeschützt. Es gibt einfach keine API zum Ändern der Sicherheitsstufe, zum Isolieren eines Ports oder zum Auswerfen eines Geräts. Dies wurde in Version 1 nicht vergessen – es wurde bewusst weggelassen. Wenn externer Code (hier ein LLM) den Schutzstatus eines Sicherheitstools neu schreiben würde, würde dies das Vertrauen aller Benutzer zerstören.
  • Es öffnet keinen Socket. Es registriert weder einen Dienst noch lauscht es. Es liest eine Zeile von stdin, gibt eine Zeile von stdout zurück und dann beendet der Client den Prozess.
  • Es wird nichts gesendet. Alle Diagnosen sind im Mac abgeschlossen.
  • Es liest Einstellungen aus einer anderen Domäne. UserDefaults(suiteName: "com.tetsuharu.RoamSwitch") liest die Domäne der App explizit (ihre eigene Bundle-ID-Domäne ist leer). Es liest nur; es schreibt nicht.

Die Werkzeuge, die es offenlegt

Die Tools tools/list-Rückgaben und die von ihnen zurückgegebenen Daten
WerkzeugWas es zurückgibtVerkehr
get_security_reportEine 18-Punkte-Prüfung (FileVault / SIP / Gatekeeper / Auto-Update / XProtect / Firewall / Wi-Fi-Verschlüsselung / ARP / Gateway-ARP-Sperre / SSH-Konfigurationsprüfung / Sudo-NOPASSWD-Prüfung / offengelegte Ports / Guard-Konfiguration und mehr) mit einer Bewertung und Korrekturempfehlungen pro PunktNur lokal
get_exposed_portsEine Liste der lauschenden TCP-Ports. Für alles, was über „localhost“ hinaus verfügbar gemacht wird, wird ein Querverweis auf eine Datenbank mit bekanntermaßen gefährlichen Diensten erstellt und CORS/Header mit einer HTTP-Prüfung auf 127.0.0.1:port (lokal, geschlossen) überprüft.Nur die Sonde auf 127.0.0.1
get_guard_statusDer Ein-/Aus-Status der Pro-Auto-Response-Guards (Portanomalie/ARP/USB/Bluetooth/Web+Mail-Download/DNS-Bedrohungsschutz), die aktuelle Schutzstufe und der Status des vertrauenswürdigen NetzwerksNur lokal
audit_url_safetyEine Beurteilung einer URL für Phishing/Homograph (Unicode-Spoofing)/Marken-Subdomain-Spoofing/Hochrisiko-TLD/Klartext-HTTP. Es ist synchron und vollständig offline (analyzeURL; es folgt keinen Weiterleitungen)Keine
get_app_helpEine Volltextsuche in der gebündelten Wissensdatenbank (Funktionsspezifikationen/Einstellungen/Fehlerbehebung/Erklärungen zu Benachrichtigungsmeldungen)Keine
audit_secretsErkennt offengelegte API-Schlüssel und private Schlüssel in Text, Dateien oder Verzeichnisbäumen (Treffer werden in der Ausgabe maskiert).Keine
audit_security_logsWertet aktuelle Sicherheitslogs aus (Mac: fehlgeschlagene Sudo-Authentifizierungen, SSH-Brute-Force-Versuche, Gatekeeper-Blockaden, XProtect-Erkennungen usw. / Linux: fehlgeschlagene Sudo-Authentifizierungen, SSH-Brute-Force, Firewall-Blockaden, AppArmor-Ablehnungen, ClamAV-Erkennungen usw.), maskiert automatisch sensible Daten wie API-Schlüssel und Tokens und liefert zusätzlich Ergebnisse der Log-Template-basierten Erkennung neuer Muster sowie der Häufigkeitsanomalie-Erkennung (statistische Spitzen).Nur lokal
run_active_vuln_scanNicht-destruktive, ausschließlich auf 127.0.0.1 beschränkte aktive Schwachstellenprüfung. Das einzige Tool, das das Netzwerk nutzt — standardmäßig deaktiviert und nur nach Zustimmung in den Einstellungen.Nur 127.0.0.1 (standardmäßig aus)
run_package_cve_scanGleicht installierte Pakete (Mac: Homebrew / Linux: dpkg, dnf, zypper, pacman) mit einer lokalen CVE-Zuordnung ab. Es findet überhaupt keine Netzwerkkommunikation statt.Keine
run_package_cve_scan_languagesGleicht Abhängigkeits-Lockfiles für npm, PyPI, crates.io, RubyGems, Packagist, Go und Maven mit derselben lokalen CVE-Zuordnung ab. Es findet überhaupt keine Netzwerkkommunikation statt.Keine
get_quarantine_statusLiefert den Inhalt des Malware-Quarantäne-Tresors: ursprünglicher Pfad, erkannter Bedrohungsname, Zeitpunkt und Größe.Nur lokal
get_canary_statusLiefert den Zustand der Ransomware-Köderdateien (Canary) sowie bis zu die 50 jüngsten erkannten Vorfälle.Nur lokal
get_notification_historyGibt den Verlauf der von RoamSwitch gesendeten Benachrichtigungen (Sicherheitslog-Auffälligkeiten, ClickFix-Erkennungen u. a.) der letzten 7 Tage zurück, neueste zuerst.Nur lokal
get_port_anomaly_incidentsLiefert den Baseline-Zustand des Port-Anomalie-Schutzes, aktuell automatisch blockierte Ports und bis zu die 50 jüngsten Vorfälle. Die Antwort weist ausdrücklich darauf hin, dass die aktuell blockierten Ports eine zeitstempellose Momentaufnahme sind, die sich von der zeitgestempelten Vorfallshistorie unterscheidet.Nur lokal
get_runtime_threat_statusGibt an, ob dieser Mac wegen eines XProtect-Malwarefunds per Air-Gap isoliert wurde, und nennt den auslösenden Vorfall. Bei aktivem Air-Gap zuerst prüfen.Nur lokal

Im Feld instructions in der Antwort initialize heißt es auch deutlich: „Die Sicherheitsstufe kann nicht geändert, Ports nicht isoliert oder Geräte ausgeworfen werden“, um die Funktion zu kommunizieren Grenze zum clientseitigen LLM. Die MCP-Ressourcen (roamswitch://docs/*) sind schreibgeschützt Auch Markdown-Dokumente.

Eine bei einer Fire-Drill-Übung mit einem lokalen LLM entdeckte und behobene Fehlzuordnung

Im September 2026 führten wir mit diesem MCP-Server eine Übung durch, bei der ein lokales LLM (Qwen 3.8 27B) einen Vorfall untersuchen sollte, und entdeckten dabei einen Fall, in dem das Modell die von get_port_anomaly_incidents zurückgegebenen Daten falsch interpretierte und eine unabhängige, ältere Portsperrung in die Erzählung eines laufenden Vorfalls einflocht. Die Ursache: Eine zeitstempellose Momentaufnahme der aktuell blockierten Ports wurde in derselben Antwort wie die echte, zeitgestempelte Vorfallshistorie zurückgegeben, ohne dass etwas zwischen beiden unterschied. Die Korrektur fügt explizite Hinweisfelder hinzu, die kennzeichnen, welches Feld eine Zeitleiste und welches eine Momentaufnahme ist. Beim erneuten Ausführen desselben Szenarios mit demselben Modell zitierte dieses den Wortlaut des Hinweises und lehnte es ausdrücklich ab, den alten Port dem aktuellen Vorfall zuzuordnen. Die Wirksamkeit der Korrektur wurde sowohl durch einen automatisierten Regressionstest als auch durch die erneute Ausführung mit dem echten lokalen LLM bestätigt.

Kernpunkt: Quelle ist öffentlich

Der Quellcode dieses Servers und der von ihm verwendeten Erkennungslogik (ARP-Überwachung, Port-Scanning, Port-Audit, der 18-Punkte-Gesundheitscheck, URL-Sicherheitsanalyse) wird unter github.com/lafine1211/roamswitch-mcp veröffentlicht (MIT, ein Spiegel des ausgelieferten Codes, pro Release getaggt). Sie können direkt im Code prüfen, ob er schreibgeschützt ist, was er an das LLM übergibt und dass er nichts nach außen sendet. Er enthält nicht den privilegierten Helfer, die pf-Steuerung, die eingreifenden Wachen oder die Lizenzierung – diese verbleiben im App-Repository.

Die Tests sind ebenfalls im Lieferumfang enthalten – gespiegelte Unit-Tests, gegnerische Eingabetests und Mutations-Fuzzing. Wird von swift test ausgeführt und in CI überprüft. Fuzzing erlebte einen unbeaufsichtigten Absturz (JSONSerialization Stapelüberläufe bei einem tief verschachtelten JSON-Objekt); es ist mit fixiert eine Verschachtelungstiefenprüfung vor dem Parser und aufgezeichnet in SECURITY_TESTING.md.

§9

Der Token

  • Es verwendet Ed25519 (Curve25519-Signaturen). Der öffentliche Schlüssel ist in die App eingebettet (LicenseVerifier.embeddedPublicKeyBase64). Der entsprechende private Schlüssel existiert nur im Lizenz-Backend (eine Firebase Functions-Umgebungsvariable) und befindet sich nicht im Repository.
  • ___
  • Es ist so konzipiert, dass es beim Schließen fehlschlägt. Wenn der eingebettete Schlüssel fehlt oder fehlerhaft ist oder wenn die Signatur oder der kanonische JSON nicht erstellt werden kann, wird das Ergebnis nicht „verifiziert“ – es wird invalidSignature zurückgegeben.

Gerätebindung

device_hash = SHA-256( "RoamSwitch-LifetimeSalt-v1" : lowercase(IOPlatformUUID) )

Die reine Hardware-UUID wird nicht an den Server gesendet. In dem seltenen Fall, dass IOKit kein a zurückgibt UUID, es greift auf eine zufällige UUID zurück, die in UserDefaults gespeichert ist. Zum Zeitpunkt der Überprüfung, wenn die Der device_hash des Tokens stimmt nicht mit dem aktuellen Geräte-Hash überein. Das Ergebnis ist deviceMismatch.

Es funktioniert offline

Kernpunkt: Funktioniert ohne Server

Alles, was validateSavedLicense() beim Start tut, ist, das Token aus dem Schlüsselbund zu lesen und Überprüfen Sie es lokal mit dem eingebetteten öffentlichen Schlüssel. Es stellt keine Verbindung zum Netzwerk her. Wenn die Wenn der Lizenzserver jemals heruntergefahren wird, funktionieren die Pro-Funktionen weiterhin auf einem Mac, der bereits aktiviert ist. Der Server wird nur für eine erneute Aktivierung und für eine explizite Deaktivierung kontaktiert. Die Deaktivierungsbenachrichtigung an den Server ist die beste Lösung – selbst wenn sie fehlschlägt, erfolgt die lokale Deaktivierung wird immer abgeschlossen.

Der Standardwert ist ein einmaliger (lebenslanger) Kauf; expires_at wird nur überprüft, wenn is_lifetime ist falsch. Die Anzahl der Sitzplätze wird nach Stufe ausgedrückt – 2 für Personal Pro, 5 für Team.

§10

Unterzeichnung und Beglaubigung (scripts/release.sh)

  1. Führen Sie xcodebuild archive aus (Release, manuelle Signatur, Entwickler-ID-Anwendung).
  2. Export mit -exportArchive als method: developer-id.
  3. Führen Sie nach notarytool submit --wait stapler staple in der .app aus.
  4. Überprüfen Sie mit spctl -a -t exec -vv.
  5. Nach dem Heften erneut komprimieren, um das Sparkle-Update-Artefakt zu erstellen (damit das Beglaubigungsticket enthalten ist und es ohne Gatekeeper-Warnung offline ausgeführt wird).
  6. Erstellen Sie die DMG, beglaubigen Sie die DMG, beglaubigen Sie sie, heften Sie sie ebenfalls zusammen und überprüfen Sie sie mit stapler validate.

Updates (Sparkle 2.9.6)

Aktualisieren Sie die Einstellungen in Info.plist
SchlüsselWert
SUFeedURLhttps://lafine.net/updates/appcast.xml
SUPublicEDKeyCNxzwijMzMCJzliId76Yl88S/9np6t/xg/zQ9YbYzHs=
SUEnableAutomaticCheckswahr
SUScheduledCheckInterval86400

Bevor ein Update angewendet wird, wird die im Appcast aufgeführte EdDSA-Signatur überprüft gegen den in der App eingebetteten SUPublicEDKey. Der private Signaturschlüssel existiert nur in die Build-Umgebung. Der Appcast wird über HTTPS bereitgestellt. Delta-Updates sind signaturverifiziert auf die gleiche Weise.

Kernpunkt: Der Appcast ist von Natur aus öffentlich

Die Tatsache, dass die URL appcast.xml öffentlich ist, ist an sich keine Schwäche. Sein Inhalt sind nur Versionsnummern, Versionshinweise, Download-URLs, Dateigrößen und die EdDSA-Signatur von Jeder Build – nichts Geheimnisvolles. Der Vertrauensanker ist nicht „Ist der Appcast während der Übertragung authentisch“, sondern Überprüfen der Signatur des Artefakts mit dem in die App integrierten öffentlichen Schlüssel. Ein Angreifer, der es kann Ersetzen Sie den Appcast vollständig (MITM, DNS-Hijacking, Kompromittierung des Webhosts) und können Sie immer noch nicht pushen ein bösartiges Update ohne den Signaturschlüssel. Gatekeeper (Entwickler-ID und Beglaubigung) ist ein zweites Tor.

Es bleiben zwei Risiken bestehen. Einer davon ist, dass Updates nicht eintreffen, weil der Host ausgefallen ist oder der Appcast defekt ist (Es passiert keine fehlerhafte Installation – Sie werden einfach nicht aktualisiert). Der andere ist ein Freeze-Angriff ein Sicherheitsupdate bewusst zurückhält. Sparkle 2.x lehnt Downgrades und Wiederholungen durch Überprüfung ab Versionsbestellung, aber ein vollständiger Schutz gegen das Einfrieren erfordert einen dedizierten Update-Server mit Ablauf. Das steht auf unserer Liste.

§11

Womit RoamSwitch umgehen soll

  • Sondierungen und Angriffe von einem Angreifer im selben LAN oder von einem kompromittierten IoT-Gerät aus. Die Reaktion erfolgt durch Tarnung, Überwachung exponierter Ports und Isolierung von außen.
  • Exposition in einem Netzwerk, dem Sie nicht vertrauen. Es stoppt automatisch die Freigabe von Diensten und AirDrop.
  • ___ All Pro, standardmäßig deaktiviert (Erkennung ist standardmäßig aktiviert).
  • Auffinden von Entwicklungsservern und Datenbanken (Redis, MongoDB, Elasticsearch usw.), die auf 0.0.0.0 ohne Authentifizierung verfügbar sind, und Blockieren dieser von außen.
  • Erkennen Sie Ransomware-ähnliche, nicht autorisierte Verschlüsselungsaktivitäten frühzeitig und stoppen Sie den gesamten Datenverkehr (nicht auf Signaturen angewiesen).
  • BadUSB und physischer Tastatur-Genehmigungsschutz (USBKeyboardGuard, CGEventTap + IOKit), der Tastenanschläge von nicht zugelassenen USB-Tastaturen/-Kabeln (Rubber Ducky, O.MG-Kabel usw.) abfängt und verwirft, um automatisierte Befehlsinjektionsangriffe zu verhindern.
  • Eine Genehmigungsaufforderung für unbekannten USB-Speicher (ein nicht erkanntes Laufwerk wird schreibgeschützt gehalten und nicht sofort ausgeworfen) und ein automatischer ClamAV-Scan auf angeschlossenem Speicher (optional).
  • Erkennt sensible API-Schlüssel (OpenAI, Anthropic, GitHub, AWS usw.) in der Zwischenablage vollständig lokal und verhindert ein versehentliches Einfügen in ein Webformular oder einen KI-Chat, bevor es passiert.
  • Erkennt und warnt vor gefährlichen KI-Modelldateien im Pickle-Format (Risiko der Ausführung beliebigen Codes), die von Hugging Face oder aus dem Web heruntergeladen wurden.
  • Die branchenübliche EICAR-Testsignatur und gut dokumentierte Reverse-Shell-Einzeiler in heruntergeladenen Dateien (StaticSignatureScanner, ab 1.8.7, funktioniert auch ohne installiertes ClamAV).
  • Ein neu registrierter LaunchAgent/LaunchDaemon, der einen rohen Skriptinterpreter direkt aufruft (PersistenceMonitorGuard, ab 1.8.7).
  • „ClickFix“-artige Angriffe, bei denen ein gefälschter Warnbildschirm dazu verleitet, selbst einen Befehl im Terminal auszuführen – erkannt anhand bekannter bösartiger Befehlsmuster im Shell-Verlauf, was einen Notfall-Air-Gap auslöst (ClickFixGuard, ab 1.8.7, Pro, standardmäßig deaktiviert).
  • Erkennt und benachrichtigt sofort, wenn ein Container mit einer Container-Escape-riskanten Docker-Konfiguration startet, etwa im --privileged-Modus oder mit /var/run/docker.sock eingebunden (DockerEventGuard, ab 1.8.9, Pro, standardmäßig deaktiviert, nur Benachrichtigung).
  • Geheimnis-/API-Schlüssel-Leck-Audit, das jetzt nicht nur eingefügten Text, sondern auch rekursives Scannen ganzer Ordner abdeckt (SecretLeakAuditor, Ordner-Scan hinzugefügt in 1.8.9, vollständig auf dem Gerät).

Was wir bewusst nicht getan haben

  • Es ist kein Ersatz für Antivirus. ClamAV und XProtect werden als Hilfsmittel verwendet; RoamSwitch allein ist kein Allzweck-Malware-Detektor.
  • Wir haben uns entschieden, das EndpointSecurity-Entitlement nicht zu beantragen. Die Genehmigungsraten für ein individuelles Apple-Developer-Konto sind niedrig, und jede Funktion, die tatsächlich eine Pre-Exec-Blockierung benötigt (z. B. ES_EVENT_TYPE_AUTH_EXEC), wird als geschlossenes Nicht-Ziel behandelt, solange das gilt. Anstelle der Ausführung selbst zu stoppen, haben wir ohne das Entitlement das praktisch Machbare als nachträgliche Erkennung umgesetzt: statische Signaturerkennung, Autostart-Überwachung und ClickFix-Abwehr.
  • Es ist keine Garantie. Es handelt sich um eine Ebene in einem Defense-in-Depth-Stack, nicht um etwas, das „Ransomware vollständig verhindert“. Auch Marketingtexte werden unter dieser Prämisse überprüft.
  • Ein bereits kompromittiertes Root oder Kernel kann nicht geschützt werden. Wenn ein Angreifer bereits über Root verfügt, kann er auch die Pf-Regeln des Helfers entfernen.
  • ___ Der VPN-Tunnel (§5) ist die Antwort, wenn Sie diese Annahme nicht annehmen möchten: Selbst wenn L2 vergiftet ist, werden die Inhalte verschlüsselt und der Kill-Switch verhindert, dass Klartext durchsickert. Es ist kein Ersatz für Unternehmens-DHCP-Snooping oder dynamische ARP-Inspektion.
  • Es wird kein VPN-Server bereitgestellt. Die Tunnelfunktion verwendet eine WireGuard-Konfiguration, die der Benutzer bereitstellt; RoamSwitch wird kein VPN-Anbieter.

Angriffsfläche, die durch die Installation von RoamSwitch hinzugefügt wird

Angriffsfläche hinzugefügt und wie sie eingedämmt wird
AngriffsflächeWie es enthalten ist
Ein LaunchDaemon, der als Root ausgeführt wird, und sein Mach-Dienst (com.tetsuharu.RoamSwitch.Helper) Die Bedienoberfläche ist auf HelperProtocol festgelegt (Tabelle §3). Es gibt keinen Kanal für beliebige Befehle. Verbindungen werden durch eine Codesignaturanforderung unter Verwendung von audit_token autorisiert.
Wenn RoamSwitch.app selbst kompromittiert wird, gehen alle Vorgänge des Helfers an den Angreifer über Die gehärtete Laufzeit ist aktiviert und die App erhält keine unnötigen Berechtigungen. Ausgehender Datenverkehr ist auf die acht oben genannten Pfade beschränkt (der sechste nur, wenn der Benutzer ein VPN konfiguriert, der siebte nur, wenn die RoamSwitch Sensor-Kopplung aktiviert ist). Wir planen, dies von einem Dritten überprüfen zu lassen.
Die systembinären Pfade, die der Helfer erzeugt Absolute Pfade wie /sbin/pfctl werden direkt angegeben, ohne Abhängigkeit von PATH. Auch die Argumente sind fest codiert (abgesehen von Portnummern, DNS-Strings, den ARP-IP/MAC-Paaren und der VPN-Endpunkt-IP – die alle formatvalidiert sind).
Link Guard wird neu geschrieben /etc/hosts (setLinkGuardSinkhole) Schreibvorgänge sind auf einen durch Trennzeichen getrennten verwalteten Abschnitt beschränkt. Zeilen außerhalb davon bleiben wörtlich erhalten. Domänen werden normalisiert und validiert, IPs und Junk werden gelöscht, die Liste ist auf 60.000 begrenzt und die Datei wird über eine temporäre Datei + atomares Ersetzen geschrieben. Es werden nur eindeutige Fälle (Bedrohungs-Feed-Auflistung oder Markennamen-Homographie) ausgewertet, die von einer ausschließlich lokalen Urteilsmaschine entschieden werden. Die Sperrliste selbst stammt aus dem signaturverifizierten Bedrohungs-Feed (Feed-dedizierter Schlüssel).
Bedrohungs-Feed-Abruf von Link Guard (ein täglicher Empfang nur GET) Ein Abruf einer statischen Datei ohne Abfragezeichenfolge und ohne Bezeichner. Das Manifest und der Feed-Text sind beide Ed25519-verifiziert und ein Abruf, der die Überprüfung nicht besteht, wird verworfen (kein Fallback auf nicht signierte Daten). „Auto-Update: Aus“ entfernt den Pfad vollständig.
Präventiver ARP/NDP-Pin (lockGatewayARP) Nur die Neighbor-Cache-Einträge für „das Gateway, den IPv6-Router, On-Link-DNS“ werden angeheftet. Die übergebenen IP/MAC-Paare werden formatvalidiert und mit dem Anforderungssatz abgeglichen (es werden niemals Einträge von selbst hinzugefügt). Es läuft nur in nicht vertrauenswürdigen Netzwerken; Pro, standardmäßig deaktiviert. Das Trust-on-First-Use-Limit ist in §11 „Was wir beschlossen haben, nicht zu tun“ angegeben.
VPN-Tunnel (wireGuardImport/Up/…, Homebrew wireguard-tools) Der .conf wird vom Helfer unter 0600 gespeichert. Die Endpunkt-IP wird von der App aufgelöst und an den Helfer übergeben (der Helfer löst niemals einen beliebigen Hostnamen auf). Ziel und Inhalt des Tunnels unterliegen der Kontrolle des Benutzers. Die Funktion ist deaktiviert, wenn wireguard-tools nicht installiert ist. Pro, standardmäßig deaktiviert. Der Kill-Switch geht über PFRulesetCoordinator (§4).
Der MCP-Server übergibt den Systemstatus an einen LLM (einen verwirrten Stellvertreter). Es ist schreibgeschützt, es ist keine Schreib-API implementiert. URL-Prüfungen sind offline. Auf die Einstellungsdomäne wird schreibgeschützt verwiesen.
Kaperung des Update-Pfads EdDSA-Signaturüberprüfung (SUPublicEDKey) sowie ein gebündeltes Beglaubigungsticket. Der Appcast erfolgt über HTTPS.

Anhang A

Alles, was in diesem Dokument angegeben ist, kann mit den folgenden Befehlen anhand des verteilten Artefakts überprüft werden.

Unterzeichnung und notarielle Beglaubigung

# Developer-ID-Signatur und Team-ID
codesign -dvvv /Applications/RoamSwitch.app 2>&1 | grep -E 'Authority|TeamIdentifier|flags'

# Ob das Notarization-Ticket gestapelt (staple) ist
stapler validate /Applications/RoamSwitch.app
spctl -a -t exec -vvv /Applications/RoamSwitch.app

# Signatur des mitgelieferten Helpers / MCP-Servers
codesign -dvvv /Applications/RoamSwitch.app/Contents/MacOS/RoamSwitchHelper
codesign -dvvv /Applications/RoamSwitch.app/Contents/MacOS/RoamSwitchMCPServer

Berechtigungen (keine Berechtigung zum Senden über das Netzwerk)

codesign -d --entitlements :- /Applications/RoamSwitch.app/Contents/MacOS/RoamSwitchHelper
codesign -d --entitlements :- /Applications/RoamSwitch.app/Contents/MacOS/RoamSwitchMCPServer
# → Ein leeres Entitlements-Dictionary. Keine app-sandbox-/network-client-Schlüssel.

Den Verkehr messen

# tcpdump parallel mitlaufen lassen, um zu bestätigen, dass bei normaler Nutzung kein Traffic entsteht
sudo tcpdump -i any -n 'host not 127.0.0.1' and 'not port 53'
# Kein Traffic außer Lizenzaktivierung, Update-Prüfungen und ClamAV-Definitionsupdates

Eine strengere, automatisierte Prüfung mit Zuordnung pro Prozess finden Sie unter rs-zerotel-audit.sh in roamswitch-support/audit/

Verteidigungsarchitektur und Penetrationstests (5 Verteidigungsgrenzen)

# Verifiziert automatisch in einem Durchgang: XPC-Autorisierungsgrenze, pf-Air-Gap-Priorität, Port-Expositionserkennung, MCP-Nur-Lesen, ARP-Überwachung
git clone https://github.com/lafine1211/roamswitch-support
cd roamswitch-support/audit
./rs-defense-audit.sh all

Live-Penetrationstests und mehrschichtiges Verteidigungsaudit von einer macOS-VM: RESULTS-DEFENSE-2026-08-30

Überprüfung des DNS-Bedrohungsschutzes (Quad9-Malware und C2-Blockierung).

# Abfrage der offiziellen Quad9-Testdomain zur Verifikation der Bedrohungsblockierung
nslookup test.dns9.quad9.net
# → Sollte ** server can't find test.dns9.quad9.net: NXDOMAIN liefern, d. h. die Namensauflösung ist blockiert

Überprüfung des Web- und Mail-Download-Guards (ClamAV-Echtzeiterkennung).

# Die harmlose branchenübliche Antiviren-Teststring (EICAR) in Downloads erstellen
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > ~/Downloads/eicar_test.com
# → Die FSEvents-Erkennung löst einen sofortigen ClamAV-Scan aus; es erscheint keine Benachrichtigung, "EICAR-Testsignatur erkannt (harmlos)"
#   wird nur im Benachrichtigungsverlauf erfasst. Da EICAR eine branchenübliche Testdatei und keine echte Bedrohung ist,
#   wird sie weder unter Quarantäne gestellt noch blockiert, und die Datei bleibt unverändert (nur eine echte Malware-Probe wird in den Quarantäne-Manager verschoben).

Überprüfung der statischen Signaturerkennung (ohne EndpointSecurity)

## Ein Lehrbuch-Reverse-Shell-Einzeiler aus öffentlichen Offensive-Security-Referenzen (harmlos, wird nie ausgeführt)
echo 'bash -i >& /dev/tcp/127.0.0.1/4444 0>&1' > ~/Downloads/rs_test.sh
## → Auch ohne installiertes ClamAV erscheint eine Benachrichtigung „Gefährliche Download-Datei unter Quarantäne gestellt“, und die Datei wird
##   sofort in den Quarantäne-Ordner verschoben (unabhängig von ClamAVs Signaturdatenbank)

Überprüfung der neuen Autostart-Überwachung (PersistenceMonitorGuard)

# Einen harmlosen LaunchAgent anlegen, der einen rohen Skriptinterpreter direkt aufruft (wird nie tatsächlich ausgeführt)
cat > ~/Library/LaunchAgents/com.example.selfcheck.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.example.selfcheck</string>
  <key>ProgramArguments</key><array><string>/bin/bash</string><string>-c</string><string>echo hi</string></array>
</dict></plist>
EOF
# → Innerhalb weniger Sekunden sollte eine Benachrichtigung „Neue Autostart-Registrierung erkannt“ erscheinen. Danach entfernen:
rm ~/Library/LaunchAgents/com.example.selfcheck.plist

Link Guard (blockiert Phishing-Verbindungen)

# Ob der verwaltete Abschnitt vorhanden ist (2 BEGIN/END-Zeilen bei Pro + Standardmodus)
sudo grep -c 'RoamSwitch link guard' /etc/hosts

# Inhalt des Abschnitts und Anzahl der Sinkholes
sudo sed -n '/BEGIN RoamSwitch link guard/,/END RoamSwitch link guard/p' /etc/hosts | head -4
sudo sed -n '/BEGIN RoamSwitch link guard/,/END RoamSwitch link guard/p' /etc/hosts | grep -c '^0\.0\.0\.0'

# Ob es tatsächlich blockiert wird (mit einem Eintrag aus dem Abschnitt geprüft; harmlos)
D=$(sudo sed -n '/BEGIN RoamSwitch/,/END RoamSwitch/p' /etc/hosts | awk '/^0\.0\.0\.0/{print $2; exit}')
dscacheutil -q host -a name "$D"   # → ip_address: 0.0.0.0 (Namensauflösung ist blockiert)

# Auch bestätigen, dass der obige Abschnitt über Menü → „Linkschutz" → „Aus" verschwindet

Der Nur-Empfangs-Bedrohungs-Feed (signaturverifiziert)

# Öffentlicher Feed und Manifest (von jedem abrufbar und überprüfbar)
curl -s https://lafine.net/updates/v1/manifest        # version/generated/threatfeed{...}
curl -sI https://lafine.net/updates/v1/manifest.sig   # → text/plain
# Es wird nur ein GET ohne Query-String, Cookies oder Identifikatoren gesendet. Mit parallel laufendem tcpdump überprüfbar.

Präventive ARP/NDP-Sperre (§5, 1.7.5+)

# Mit aktivierter präventiver Sperre mit einem nicht vertrauenswürdigen Netzwerk verbinden → auf permanent-Einträge prüfen
arp -an | grep -i permanent          # Gateway und andere IPs werden als (permanent) aufgeführt
ndp -an | grep -i 'P '               # IPv6-Seite (P = permanent)
sudo cat "/Library/Application Support/RoamSwitch/gateway_arp_lock.json"  # Die Menge der aktuell fixierten IP→MAC-Zuordnungen
# Sperre über das Menü aufheben → das Obige sollte verschwinden

VPN-Tunnel + Kill-Switch (§5, 1.7.6+)

# Setzt wireguard-tools voraus (über Homebrew)
brew list wireguard-tools >/dev/null && echo "wireguard-tools: OK"

# VPN in einem nicht vertrauenswürdigen Netzwerk aktivieren → bevor der Tunnel steht, befindet sich pf im Kill-Switch-Zustand
sudo pfctl -sr | grep -E 'block drop all|pass .*(utun|udp)'   # block drop all + eine begrenzte Menge an pass-quick-Regeln

# Nachdem der Tunnel steht (wg-quick up bereits ausgeführt)
wg show                              # handshake / transfer läuft
route -n get default | grep interface  # → utunN (die Standardroute ist der Tunnel)
# VPN deaktivieren → Kill-Switch wird aufgehoben, pf kehrt in den vorherigen Zustand zurück

Der privilegierte Helfer selbst

# Der registrierte LaunchDaemon
sudo launchctl print system/com.tetsuharu.RoamSwitch.Helper

# Die aktuell geladenen pf-Regeln (tatsächlicher Zustand von Air-Gap / Port-Guard)
sudo pfctl -sr

# Das Zustandsverzeichnis des Helpers
ls -la "/Library/Application Support/RoamSwitch/"

Die Antwort des MCP-Servers (Offline-Prüfung)

BIN=/Applications/RoamSwitch.app/Contents/MacOS/RoamSwitchMCPServer
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
              '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | "$BIN"
# Liefert serverInfo und die Definitionen der 5 Tools zurück. Es entsteht keine Netzwerkverbindung.

Die Quelle und Tests des MCP-Servers

git clone https://github.com/lafine1211/roamswitch-mcp
cd roamswitch-mcp
swift build -c release        # Derselbe Quellcode wie in der ausgelieferten Binärdatei
swift test                    # Unit-, Adversarial-Input-, stdio- und Mutations-Fuzzing-Tests
# Testinhalte und gefundene Probleme siehe SECURITY_TESTING.md

Gerätekennung

# Der Rohwert, der an das Token gebunden ist (gesendet wird nur ein gesalzener SHA-256)
ioreg -d2 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}'
RoamSwitch Architektur-/Sicherheits-Whitepaper v1.5 · Geltungsbereich 1.9.28 (Build 85) · Lafine Systems Design · 2026-09-15
Fehler oder Auslassungen melden Sie bitte über lafine.net/contact.html.