§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.
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.
| Ausführbar | Privileg | Kann | Geht 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 |
Alles andere. Es gibt keine Schnittstelle zum Ausführen beliebiger Befehle. Ein Entitlement für Netzwerkversand wird nicht deklariert; da der Helfer aber nicht in der Sandbox läuft, verbietet das allein keine Kommunikation (Messung des ausgehenden Verkehrs in §7) |
| RoamSwitch MCPServer |
Benutzer anmelden | Diagnosewerte lesen und formatieren, lokale Wissensdatenbank durchsuchen; Die Ergebnisse werden über stdio an den Client zurückgegeben | Einstellungen ändern, Lockdown umschalten, einen Port isolieren, ein Gerät auswerfen. Standardmäßig öffnet es keine Sockets und sendet nichts über das Netzwerk (Ausnahmen sind nur die standardmäßig deaktivierte npm-Signaturprüfung und die Schwachstellendiagnose gegen diesen Mac selbst, 127.0.0.1; siehe §8). Ein Entitlement für Netzwerkversand wird nicht deklariert; da es nicht in der Sandbox läuft, verbietet das allein keine Kommunikation |
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).
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.
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.
| Methode | Was es bewirkt | Binär/API aufgerufen |
|---|---|---|
| setBlockAll(_:) | Schaltet die Anwendungs-Firewall und den Stealth-Modus ein oder aus | /usr/libexec/ApplicationFirewall/ --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) | — |
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.sharedist 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.
Rechtetrennung im Helper und die Ausnahme zum Lesen des SSH-Protokolls
Der Helper legt sich gleich nach dem Start selbst eine vom Kernel durchgesetzte Obergrenze auf (eine Laufzeit-Sandbox, die nichts mit dem oben genannten App-Sandbox-Entitlement zu tun hat); auch die von ihm gestarteten Kindprozesse erben sie. Sie verhindert das Ersetzen von Systemprogrammen, das Registrieren eines LaunchDaemon oder LaunchAgent, das Umschreiben der Konfiguration von sudoers, PAM oder sshd, das direkte Schreiben in den lokalen Verzeichnisspeicher und das Ausführen von Programmen aus Orten, in die Benutzer, externe Volumes oder temporäre Ordner schreiben können. Nicht verhindert werden Kontoänderungen über Open Directory (dscl), und den Netzwerkverkehr schränkt sie nicht ein (dafür ist die Obergrenze nicht gedacht).
Unter dieser Obergrenze läuft /usr/bin/log nicht. Unter macOS 26 weigert sich log, innerhalb einer Sandbox zu laufen (log: Cannot run while sandboxed), und ebenso als nobody (Must be admin). Damit können weder die App des angemeldeten Benutzers noch der root-Helper in seiner Sandbox das sshd-Protokoll (das einheitliche Protokoll) lesen. Die SSH-Brute-Force-Erkennung muss dieses Protokoll lesen, deshalb gibt es in der Rechtetrennung eine Ausnahme.
Die Ausnahme ist ein kleiner root-Prozess: Bevor der Helper in seine Sandbox geht, startet er dieselbe Binärdatei mit --ssh-log-reader. Dieser Prozess nimmt nur einen Ein-Byte-Befehl (Start oder Stopp) an und startet nichts weiter als /usr/bin/log mit festen Argumenten (log stream --style ndjson --level info und einer festen Bedingung, die nur sshd-Zeilen durchlässt). Er gibt keine Umgebungsvariablen weiter, und der Aufrufer hat keine Möglichkeit, Argumente oder einen Befehl vorzugeben. Er liest und interpretiert das Protokoll nicht; die Ausgabe fließt in eine Pipe, die der Helper übergeben hat.
Logzeilen enthalten Zeichenfolgen, die ein Angreifer schreiben kann, etwa den Benutzernamen; deshalb interpretiert der root-Helper sie nicht. Er übergibt jede Zeile an einen Parse-Worker, der als nobody in einer Sandbox läuft, die Netzwerkzugriff, Dateischreibzugriffe sowie das Starten und Forken von Prozessen verbietet, und die Quelladresse stammt vom Zeilenende (IP port N), auf das der Benutzername keinen Einfluss hat. Auf einem Mac mit ausgeschalteter Entfernter Anmeldung startet dieser Prozess log nicht und liest nichts. Über die XPC-Schnittstelle des Helpers lassen sich fünf SSH-Operationen aufrufen: Einstellungen anwenden, Status, Einträge und Anmeldungen abrufen und eine Sperre aufheben. Keine davon nimmt einen Befehl entgegen.
§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
DispatchQueueausgefü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).
- Notluftspalt →
set skip on lo0undblock drop all(nichts anderes wird berücksichtigt) - VPN-Kill-Switch →
block drop allpluspass quicknur für:lo, die Tunnelschnittstelle (utunN), den UDP-Handshake zu den angepinnten Endpunkt-IP(s), DHCP und ICMP - Dev-Server-Wächter →
block drop in quick proto tcp ... port { … } - Keine →
/etc/pf.confneu laden und pf in seinen ursprünglichen Zustand zurückversetzen
- Notluftspalt →
- Nach der Anwendung zurücklesen.
pfctl -srliest die Regeln zurück, um zu bestätigen, dassblock drop alloder die Regel jedes Ports tatsächlich geladen ist. Ein Fall, in dempfctl -fstillschweigend ignoriert wurde, wird nicht als Erfolg gewertet. - Die temporäre Datei wird in einen Pfad geschrieben, der einen
UUIDenthä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.
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
| Freundlich | Umfang | Auslöser | Loopback |
|---|---|---|---|
| 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 das Air-Gap weder hängen bleibt noch ausgesessen werden kann
- Wie es endet, hängt vom Auslöser ab (ab 1.9.52). Ein manipulierter Ransomware-Köder, eine bestätigte XProtect-Erkennung und eine manuelle Isolation aus einer ARP-Warnung gelten als „hohe Sicherheit“; ClickFix, Portanomalien und Ähnliches als „niedrige Sicherheit“. Eine Isolation mit niedriger Sicherheit wird wie bisher spätestens nach 10 Minuten selbst aufgehoben. Eine mit hoher Sicherheit wird nach 10 Minuten nicht aufgehoben: Eine rein zeitgesteuerte volle Aufhebung ließe sich von einem Angreifer einfach aussitzen.
- Eine Isolation mit hoher Sicherheit bleibt bis zu einer Obergrenze (standardmäßig 1 Stunde, in den Einstellungen 5 Minuten bis 24 Stunden) vollständig geschlossen und prüft dann die Ursache. Bei Ransomware gilt die Ursache nur dann als beseitigt, wenn der verdächtige Prozess identifiziert wurde und beendet ist und sich die Köder seit der Erkennung nicht mehr verändert haben. Lässt sich das nicht bestätigen, geht sie in den „eingeschränkten Modus“ über: Neue Verbindungen bleiben gesperrt (außer Loopback und DHCP), nur das WLAN-Funkmodul wird wieder eingeschaltet, damit Sie die Lage prüfen können. Er öffnet sich nie allein durch Zeitablauf. Er öffnet sich nur, wenn Sie ihn aufheben oder die Ursache als beseitigt bestätigt ist.
- Beim Start einer Isolation werden auch bereits offene ausgehende Verbindungen getrennt. Die Zustandstabelle von pf wird geleert (
pfctl -F states); damit stoppt Verkehr, der schon vor der Isolation lief. Beim Wechsel in den eingeschränkten Modus geschieht dasselbe. - Eine durch ARP-Spoofing ausgelöste Isolation wird nur dann automatisch aufgehoben, wenn ohne jeden Datenverkehr bestätigt werden kann, dass die Ursache weg ist. Die Prüfung liest nur den ARP-Cache (sie sendet keine Pakete) und stellt die Beseitigung fest, wenn die vertrauenswürdige Gateway-MAC bei 3 aufeinanderfolgenden Prüfungen über mindestens 60 Sekunden zu sehen ist. Während der Isolation kann der ARP-Eintrag des Gateways jedoch aus der Nachbartabelle verschwinden (auf einem echten Mac bestätigt); dann lässt sich die Ursache nicht bestätigen. In diesem Fall bleibt die Isolation im eingeschränkten Modus, bis Sie sie aufheben.
- Auch wenn der Helper abstürzt, hört die Prüfung zur Aufhebung nicht auf. Ein eigener LaunchDaemon ganz ohne
KeepAlive(AirGapFailsafe) startet alle 3 Minuten für sich und trifft dieselbe Entscheidung wie der Helper (niedrige Sicherheit: Aufhebung nach 10 Minuten; hohe Sicherheit: Ursachenprüfung an der Obergrenze, dann eingeschränkter Modus). Stürzt der Helper selbst ab und verliert damit seinen eigenen Aufhebungs-Timer, bleibt dieses Sicherheitsnetz unberührt (ab 1.8.6; die Entscheidung nach Sicherheit ab 1.9.52). - 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.PathStatedes 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. - Nach einem Neustart oder dem Neuerstellen des Daemons wird es erneut angewendet. Beim Start liest der Helper den Zustand von der Festplatte mit
reapplyFromDisk()und stellt Air-Gap, Port-Wächter und Systemstandard in dieser Reihenfolge selbst wieder her. Auch der Zustand der Isolation (Sicherheit, voll oder eingeschränkt) und die verstrichene Zeit werden übernommen; die Zeitmessung läuft ab dem ersten Auslösen weiter (auf einem echten Mac durch Neustart des Helpers bestätigt). - ___ Auf dem Bildschirm wird nie fälschlicherweise „angehoben“ angezeigt.
- Sie können jederzeit die Kontrolle zurückholen: mit „Air-Gap-Isolation aufheben“ in der Menüleiste, mit der Aufhebe-Schaltfläche im Modal oder einfach durch Ausschalten des WLANs. Das Aufheben erfordert kein Pro (es funktioniert auch, wenn Pro mitten in einer Isolation abläuft).
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.
Allgemeine entropiebasierte Ransomware-Erkennung — 1.10.0, Pro, standardmäßig aktiviert
Überwacht die Ordner Dokumente, Schreibtisch, Downloads und Fotos per FSEvents und schlägt an, wenn Schreibvorgänge mit einer Shannon-Entropie über dem Schwellenwert (7,92) in einem Burst von 20 oder mehr Dateien innerhalb von 5 Sekunden auftreten. Anders als der Canary-Ansatz (Köderdatei) hängt dies nicht von der Manipulation einer Köderdatei ab, sodass auch Verschlüsselung an Orten ohne Canary-Datei erkannt wird. Erst wenn der Schwellenwert erreicht ist, wird per lsof der aktuelle Prozess ermittelt und mit einer Zulassungsliste abgeglichen (cp, mv, ditto, tar, ffmpeg, Xcode, Time Machine, gängige Browser usw.). Bei Erkennung löst es über denselben RansomwareContainmentManager wie der Canary-Guard die automatische Netzwerksperre aus.
Die Linux-Version kann Bursts pro Prozess verfolgen, da fanotify jedem Schreibereignis eine PID zuordnet. macOS hat weder fanotify noch (bewusst) EndpointSecurity, daher liest diese Implementierung über FSEvents nur den Pfad und zählt den Burst global, unabhängig vom Prozess. Einschränkung: Wenn mehrere legitime Prozesse gleichzeitig große Mengen hochentropischer Dateien schreiben (etwa bei sich überschneidenden Komprimierungs- oder Verschlüsselungsvorgängen), ist hier eher mit Fehlalarmen zu rechnen als in der Linux-Version.
Snapshots vor dem Schaden für die Ransomware-Wiederherstellung (Mac)
Ein Snapshot zum Zeitpunkt der Erkennung enthält bereits alle Dateien, die davor verschlüsselt wurden, und ist daher kein Rückweg. RoamSwitch legt deshalb unabhängig von einer Erkennung regelmäßig APFS-Snapshots an (standardmäßig alle 6 Stunden; aus, 1, 3, 6, 12 oder 24 Stunden). Bei einer Erkennung pausieren neue Snapshots vor dem Schaden und das Aufräumen für bis zu 7 Tage (Aufbewahrungsmodus), damit der verschlüsselte Zustand die letzte Generation vor der Verschlüsselung nicht verdrängt. Die Wiederherstellung erfolgt immer manuell: Nur die gewählten Dateien werden nach ~/RoamSwitch-Recovered/ kopiert. Aktuelle Dateien werden nie überschrieben, eine Wiederherstellung des ganzen Volumes gibt es nicht. Zum Kopieren muss der Snapshot eingehängt werden, deshalb braucht der privilegierte Helper den Vollzugriff auf die Festplatte (Snapshots entstehen auch ohne ihn). macOS kann lokale Snapshots selbst löschen, etwa bei knappem Speicherplatz, daher ist ein Bestand über etwa 24 Stunden hinaus nicht garantiert. Das Wiederherstellungsfenster ist eine Pro-Funktion (das Anlegen der Snapshots funktioniert auch ohne Pro).
Forensisches Beweispaket — 1.10.0
Beginnt ein Notfall-Air-Gap — ausgelöst durch den Canary-Guard, den entropiebasierten Ransomware-Guard oder Ähnliches — sichert eine Hintergrundwarteschlange, die die Eindämmung selbst nicht blockiert, einen Schnappschuss der Prozessliste (ps), der Netzwerkverbindungen (lsof -i), der in den letzten fünf Minuten geänderten Dateien sowie der vom verdächtigen Prozess geöffneten Dateien unter ~/Library/Application Support/RoamSwitch/incident-evidence/<Zeitstempel>/manifest.json. Das Manifest erfasst den SHA-256 jedes Artefakts, damit spätere Manipulation erkennbar ist. Die Liste der Pakete ist über das MCP-Tool get_forensic_evidence_bundles abrufbar. Einschränkung: Da hierfür kein EndpointSecurity-Entitlement genutzt wird, werden weder Paketmitschnitte noch Speicher-/Dateideskriptor-Schnappschüsse des Prozesses erfasst.
Aufzeichnung von Prozessausführungen (Mac, Pro, standardmäßig aus)
Der privilegierte Helper startet das in macOS enthaltene /usr/bin/eslogger (exec, fork, exit) als Kindprozess und zeichnet Prozessstarts nur auf diesem Mac auf. Er beantragt die EndpointSecurity-Berechtigung nicht (es_new_client wird nie aufgerufen); RoamSwitch muss unter „Vollzugriff auf die Festplatte“ erlaubt sein (Systemeinstellungen; falls nicht aufgeführt, /Applications/RoamSwitch.app über „+“ hinzufügen). Solange die Erlaubnis fehlt, zeigt er den Status „nicht verfügbar“ an, wartet und prüft alle 60 Sekunden erneut (er wechselt nicht zu aufwendigem Polling). Er benachrichtigt nur. Er blockiert weder Ausführung noch Kommunikation und isoliert nicht.
Benachrichtigt bei diesen zehn Verhaltensweisen: ein Browser, Office- oder Mail-App startet direkt eine Shell; ein unsigniertes Binary wird aus einem temporären Ordner oder einem unter Quarantäne stehenden Ort ausgeführt; ein Einzeiler lädt herunter und leitet in eine Shell (in Kombination mit einer Roh-IP-URL, base64, eval oder deaktivierter TLS-Prüfung); osascript verwendet base64 oder eval; eine Datei wird unmittelbar nach Entfernen ihres Quarantäne-Attributs ausgeführt; ein unsigniertes Binary wird aus einem gerade geschriebenen Autostart-Eintrag (LaunchAgent oder LaunchDaemon) gestartet; ein nicht von Apple signierter Elternprozess liest ein Schlüsselbund-Geheimnis aus (etwa security find-generic-password -w); ein python3-, perl-, ruby-, php- oder pwsh-Einzeiler mit -c/-e/-Command, bei dem eine base64-/eval-Dekodierung und ein Aufruf von curl, wget, exec oder system in derselben Zeile stehen (ab 1.10.0 — base64 oder eval allein lösen dies nicht aus); und der Start eines Prozesses mit gesetzter Umgebungsvariable DYLD_INSERT_LIBRARIES (ab 1.10.0 — um keine Geheimnisse preiszugeben, wird ausschließlich der Wert dieser einen Variable gelesen; Apple-signierte Prozesse sind ausgenommen); und eine Befehlszeile, die direkt eine von RoamSwitch ausgelegte Köder-Zugangsdatendatei nennt (etwa ~/.aws/credentials oder ~/.env.backup, erkannt an der Markierung im Inhalt), zum Beispiel cat, tar oder curl -F; echte Dateien treffen nie zu, Lesezugriffe über eine Bibliothek überlässt die Regel der Honeytoken-Überwachung. Jede Erkennung trägt eine MITRE-ATT&CK-Technik-ID.
Nur Erkennungen mit hoher Schwere werden zu Bannern, gleichartige werden auf einmal pro 10 Minuten zusammengefasst (im Protokoll bleibt jedes Ereignis). Entwicklerwerkzeuge wie Claude Code und die GitHub CLI, die ihre eigenen Zugangsdaten lesen, werden standardmäßig nicht gemeldet. Liest ein anderes Programm sie, erlaubt die Aktion „Dieses Programm erlauben“ in der Benachrichtigung genau diesen Eintrag (bei Signatur nach Team ID, sonst nach Programmname, jeweils zusammen mit dem Eintragsnamen).
Das Protokoll wird nur für root lesbar gespeichert (Ordner 0700, Dateien 0600) und hält standardmäßig 200 MB und 14 Tage vor. Umgebungsvariablen werden nicht gespeichert, Kommandozeilenargumente können aber Geheimnisse enthalten. Jedes Segment wird in einer Hash-Kette versiegelt, die an den Hash des vorherigen Segments anknüpft; „Kette prüfen“ erkennt Änderungen, fehlende Segmente und entfernte Siegel (jeweils auf einem echten Mac bestätigt). Das erkennt Manipulation, es verhindert sie nicht. Das Löschen oder Zurücksetzen des neuesten Segments lässt sich nicht erkennen. Gelesen wird über das XPC des Helpers, MCP läuft über die App (mit erneuter Pro-Prüfung).
Grenzen: Ausführungen vor dem Start des Helpers oder vor dem Aktivieren der Aufzeichnung werden nicht erfasst. eslogger beobachtet im Nachhinein und kann nicht blockieren. Unter Last, etwa bei Tausenden Prozessstarts pro Sekunde, gehen Ereignisse verloren (die Anzahl wird angezeigt, der Betrieb läuft weiter). Diese Aufzeichnung ersetzt kein EDR (Endpoint Detection and Response).
Anmeldedaten-Honeytoken — 1.10.0, Pro, standardmäßig aktiviert
Platziert an drei Orten eine mit einem Erkennungsmerkmal versehene Köder-Anmeldedatei: ~/.aws/credentials, ~/.ssh/id_rsa_backup und ~/.docker/config.json. Eine dort bereits vorhandene echte Datei wird niemals überschrieben. Die Zugriffserkennung kombiniert denselben kqueue-Mechanismus (DispatchSource.makeFileSystemObjectSource) wie der Canary-Guard mit einem 30-Sekunden-Polling der Zugriffszeit, da ein open()-Ereignis ohne EndpointSecurity nicht zuverlässig abgefangen werden kann. Die Erkennung benachrichtigt nur; sie blockiert nichts und löst keine Isolation aus. Der ssh-Köder verwendet einen Namen, den ssh standardmäßig nicht sucht (nicht id_rsa), sodass ein normaler ssh-Aufruf weder gestört noch fälschlich gemeldet wird. Der AWS-Köder nutzt einen eigenen Profilnamen statt [default], der Docker-Köder zeigt auf eine nicht existierende interne Registry, und alle werden mit Modus 0600 angelegt (ab 1.10.3). Zusätzlich zu diesen dreien werden ~/.pypirc und ~/.env.backup ausgelegt (für Suchen nach PyPI-Token, .env-Dateien und KI-API-Schlüsseln). ~/.npmrc wird nicht verwendet, weil npm sie bei jedem Lauf liest, und GCP-Zugangsdaten nicht, weil eine gefälschte Datei die echte Authentifizierung stören würde. Wird ein Köder tatsächlich abgerufen, wird genau ein verwandter Köder (~/.aws/config, ~/.ssh/config oder ~/.kube/config) zusätzlich ausgelegt und ebenfalls überwacht; die Kette endet nach einem Schritt, und keine vorhandene Datei wird überschrieben.
Überwachung des Browser-Anmeldedatenzugriffs — 1.10.0, auch innerhalb von Pro Opt-in, standardmäßig deaktiviert
Überwacht per FSEvents Schreibvorgänge auf die gespeicherten Passwort-/Cookie-Datenbanken von Chrome, Brave, Edge, Vivaldi, Chromium und Firefox. Bei einem Burst identifiziert lsof den Prozess; alles außer dem Browser selbst, einem Indexer wie Spotlight oder einem Backup-Daemon zählt als Treffer. Anders als die übrigen neuen Guards wird dies durch Aktivieren von Pro nicht automatisch eingeschaltet — eine Browser-Erweiterung oder die Importfunktion eines Passwort-Managers kann es auslösen, sodass das Fehlalarmrisiko inhärent hoch genug ist, dass es standardmäßig als Opt-in ausgeliefert wird.
Kommunikation mit dem Sensor (TLS und Signaturen)
Kopplung, Audit-Anfragen und Abruf der Ergebnisse mit einem RoamSwitch Sensor (ein separates Produkt) im selben LAN laufen über TLS 1.3 mit festgesetztem Zertifikat-Fingerabdruck (SHA-256) (Sensor 0.3.9 und neuer). Der Fingerabdruck wird nicht über das Netzwerk geholt; der Nutzer tippt den auf dem Sensor-Bildschirm angezeigten Wert ein. Zertifizierungsstelle, Hostname und Ablaufdatum werden nicht geprüft, vertraut wird nur dem festgesetzten Wert. Schlägt TLS fehl, wird nicht auf Klartext ausgewichen (sonst könnte ein Man-in-the-Middle die Verbindung herabstufen). Anfragesignaturen enthalten Zeitstempel und Nonce (v2), um Wiedereinspielung zu verhindern. Nur eine alte Kopplung ohne Fingerabdruck verbindet sich weiterhin im Klartext, mit einer Warnung.
Ändert sich das Zertifikat, wird die Verbindung abgelehnt. Das Festsetzen wird nie automatisch aktualisiert: Es wird nur gespeichert, wenn der Nutzer den neuen Wert eingibt und bestätigt und eine signierte Sondierung tatsächlich per TLS gelingt. Grenze: Diese Sondierung prüft nicht per Schlüssel, ob es derselbe Sensor ist, der zuvor gekoppelt wurde. Sie setzt voraus, dass der Nutzer den auf dem Sensor-Bildschirm bestätigten Wert eingibt.
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.
Web-Shell-Erkennung in Entwicklungs-Webordnern (Web Rules)
Dateien der lokalen Webentwicklung (~/Sites, MAMP, Herd, Local, /Library/WebServer/Documents und die für den Paket-CVE-Abgleich registrierten Projektordner) werden mit denselben 18 Erkennungsregeln wie in der Linux-Edition geprüft: PHP, JavaScript, JSP und ASP. Die Regeln beschreiben nur öffentlich dokumentierte Techniken und enthalten keine aus einer echten Probe gewonnene Signatur. Es gibt drei Schichten: in die App eingebaut, ein signiertes, nur empfangendes Update einmal täglich (im bestehenden einen Abruf enthalten) und eigene Regeln in ~/Library/Application Support/RoamSwitch/rules.d (gelesen werden nur Dateien, die root oder Ihnen gehören und die Gruppe und andere nicht beschreiben können). Bereits überwachte Ordner wie Downloads werden direkt nach dem Schreiben geprüft; Webentwicklungsordner einmal täglich und auf Abruf (die tägliche Prüfung betritt node_modules und .git nicht; eine Prüfung eines gewählten Ordners betritt node_modules). Da EndpointSecurity nicht verwendet wird, kann nichts vor der Ausführung gestoppt werden: Jede Erkennung erfolgt nachträglich.
Standardmäßig wird nur critical automatisch isoliert. Ein high-Treffer lässt die Datei unangetastet und erscheint als Benachrichtigung und in einer Liste in den Einstellungen, wo Sie „nicht mehr erkennen“ wählen können (die Quarantäne-Stufe lässt sich in den Einstellungen ändern). Der Hook nach der Erkennung (~/Library/Application Support/RoamSwitch/hooks/post-detection) läuft nur, wenn er root oder Ihnen gehört und niemand sonst ihn beschreiben kann, und wird nach 30 Sekunden gestoppt. Die Kontomaßnahme (standardmäßig aus; zum Einschalten ist das Administratorpasswort nötig) sperrt die Login-Shell des Besitzers einer isolierten Datei, berührt aber weder root noch UIDs unter 501 noch angemeldete Benutzer (auch nicht Sie selbst, während Sie diesen Mac benutzen). Als root unter der eigenen Sandbox des Helfers in einer macOS-26-VM wurden die echte Shell-Änderung per dscl und ihre Wiederherstellung überprüft (die Sandbox blockiert direkte Schreibzugriffe auf dslocal, nicht aber Änderungen über dscl). Die Bestätigung per Administratorpasswort und der Aufrufweg von der App zum Helfer wurden auf einem echten Gerät noch nicht überprüft. In 114.501 Dateien eines Entwicklungsordners gab es 0 Treffer.
Ü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). EineNEFilterDataProvider-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/hostsnie neu und ordnet jeden Fluss einem Prozess zu. QUIC (UDP/443) hat kein lesbares SNI, daher wird es imblock-Modus gelöscht, wodurch der Browser gezwungen wird, auf HTTP/2 über TCP zurückzugreifen. Erfordert eine einmalige Genehmigung in den Systemeinstellungen. - ②
/etc/hostsSinkhole (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/hostsals0.0.0.0und 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
warnunten). „Offensichtliche Betrugsseiten automatisch blockieren (empfohlen)“ wird sofort entfernt. Der Standardwert ist Block ab 1.7.2. - ___ Sobald das Tippen des Benutzers
allowlist.txt/extra.txterreicht – 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. Dieblock-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/hostswird 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 -anerfasst, und der Helfer pinnt jeden alspermanent-Eintrag mitarp -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 -sist 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.jsongespeichert, 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 bei0600. Kill-Switch: pfblock drop allplus einpass quicknur fürlo, die Tunnelschnittstelle, den UDP-Handshake zu den angehefteten Endpunkt-IP(s), DHCP und ICMP. Ein nicht vollständiger TunnelAllowedIPslö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 upaus / meldet sich an / installiert es – es liesttailscale status --jsonund führttailscale set --exit-node=<node>aus. Empfohlen wird der Standalone-Build (direkter Download von tailscale.com) mit aktivierter CLI-Integration (Einstellungen → „CLI integration“ → „Install Now“, fügt/usr/local/bin/tailscalehinzu) – 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 Homebrew-Build (
brew install tailscale) wird nicht empfohlen. Das von Homebrew ausgeliefertetailscaledhat einen bekannten macOS-Fehler, durch den die Routing-Tabelle unter Umständen nicht korrekt neu geschrieben wird (tailscale/tailscale#21395, #21216) — ein Exit Node kann als „verbunden“ angezeigt werden, während der Datenverkehr weiterhin ungeschützt austritt, oder das Aufheben der Verbindung kann die gesamte Internetverbindung des Mac lahmlegen. RoamSwitch überprüft die tatsächliche Routing-Tabelle des Betriebssystems und warnt in diesem Fall, aber die Verwendung des oben genannten Standalone-Builds vermeidet das Problem von vornherein. - ___ 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 bleibttailscaledbestehen). - 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.
| Betrieb | Umsetzung | Privileg | Wie 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
| Daten | Standort | Inhalt |
|---|---|---|
| Lizenztoken | Schlüsselbund com.tetsuharu.RoamSwitch.license | Ein Ed25519-signiertes Token. kSecAttrAccessibleAfterFirstUnlock |
| App-Einstellungen / Schutz ein-aus | UserDefaults suite com.tetsuharu.RoamSwitch | Registrierungen vertrauenswürdiger Netzwerke, Schutzrichtlinien, Ausschlusslisten usw |
| PF-Zustand | /Library/Application Support/ | 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/ | Die 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/hosts | Ein 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/ | Der IP → MAC-Satz wurde durch die präventive Sperre (§5) zu permanent gemacht. Beim Entsperren gelöscht |
| WireGuard-Konfiguration | /Library/Application Support/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-UUID | Benutzerstandards | Ein Zufallswert, der nur generiert wird, wenn IOKit keine UUID zurückgibt (§9) |
| Protokolle | os.Logger / NSLog | Einheitliche Protokollierung. Es wird nichts nach außen gesendet |
Verkehr, der die Maschine verlässt (die vollständige Liste)
Es gibt nirgendwo Code, der Diagnoseergebnisse, Portinformationen, URLs oder Protokolle sammelt und sendet. Es sind weder ein Analyse-SDK noch ein Crash-Reporter-SDK eingebunden. Die einzige externe Bibliothek ist Sparkle (Updates). Ins Netzwerk gehen die folgenden acht Wege, dazu die unter der Tabelle beschriebenen, vom Benutzer ausgelösten Funktionen, standardmäßig deaktivierten Funktionen und der DNS-Bedrohungsschutz, und sonst nichts (der sechste nur, wenn der Benutzer ein VPN konfiguriert, der siebte nur, wenn die RoamSwitch Sensor-Kopplung aktiviert ist).
| Verbindung | Ziel | Wenn es passiert | Was 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, Gerätename (der „Name“ in den Systemeinstellungen), App-Version. Bei der Freigabe nur Schlüssel und Geräte-Hash. Persönliche Daten verarbeitet beim Kauf Stripe; die App verarbeitet sie nicht |
| Update-Prüfung | lafine.net /updates/appcast.xml |
Sparkle prüft alle 24 Stunden (und beim Start, wenn die letzte Prüfung mindestens 24 Stunden zurückliegt). Standardmäßig immer aktiv; es werden keine Systeminformationen gesendet | 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/ |
In der Pro-Version, wenn „Automatische Aktualisierung“ des Link-Schutzes eingeschaltet ist (Standard): alle 24 Stunden (und beim Start). Mit ausgeschalteter „Automatischer Aktualisierung“ entfällt dieser Pfad | Nur GET. Keine Abfragezeichenfolge, keine Cookies, nichts, was das Gerät identifiziert (der Standard-User-Agent enthält Namen und Version der App sowie die macOS-Version). Eine reine Empfangs-Datei, statisch und signiert; Manifest und Feed-Inhalt werden mit Ed25519 geprüft. Der Signaturschlüssel ist ausschließlich für den Feed bestimmt und ein anderer Schlüssel als der SUPublicEDKey der App-Updates (so bleibt ein Leck auf „eine fehlerhafte Sperrliste“ begrenzt) |
| Aktualisierungsdaten für Paket-CVE-Abgleich / aktive Schwachstellenprüfung | lafine.net /updates/v1/manifest |
Beim App-Start (wenn der letzte Abruf mindestens 30 Tage zurückliegt). Die Prüfung erfolgt alle 24 Stunden, der eigentliche Abruf einmal alle 30 Tage. 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; das gilt für alle Benutzer einschließlich der Free-Version. 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 (der Standard-User-Agent enthält Namen und Version der App sowie die macOS-Version). 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 | Wenn der Benutzer ClamAV installiert hat. In der Pro-Version startet freshclam automatisch beim Start, alle 24 Stunden und bei autonomen Kontrollläufen; in der Free-Version nur, wenn im Menü „Virendefinitionen aktualisieren“ gewählt wird |
Der übliche Definitionsabruf von ClamAV. Er enthält keine von RoamSwitch stammenden Informationen (die standardmäßigen Kennungen von ClamAV selbst können enthalten sein) |
| 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) |
„Zero Telemetry“ bedeutet hier, dass keine Telemetrie Nutzungsdaten oder Diagnoseergebnisse sammelt und sendet. Es bedeutet nicht, dass überhaupt kein Netzwerkverkehr stattfindet. Die acht Wege in der Tabelle oben und die unter der Tabelle beschriebenen Funktionen existieren tatsächlich. Jeder von ihnen wird jedoch vom Benutzer ausgelöst, ist ein signaturgeprüfter, rein empfangender Abruf oder eine Kommunikation mit einem vom Benutzer gewählten externen Dienst (die ClamAV-Verteilserver, ein Schutz-DNS-Anbieter, die geprüfte URL usw.); Diagnoseergebnisse, Ports und Dateiinhalte auf dem Mac werden nicht an den Entwickler gesendet.
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.
Einige Kommunikationswege stehen nicht in der Tabelle. Über keinen davon werden Diagnoseergebnisse oder Dateiinhalte an den Entwickler gesendet. (1) Der DNS-Bedrohungsschutz der Pro-Version stellt das System-DNS auf Quad9, Cloudflare, AdGuard oder CleanBrowsing um (Standardbereich: „unterwegs / nicht vertrauenswürdiges WLAN“). Solange er aktiv ist, gehen Namensauflösungsanfragen an diesen Anbieter. (2) Die npm-Signaturprüfung der Pro-Version fragt bei jedem Lauf nach einer Bestätigung und fragt dann die npm-Registry ab. (3) Die aktive Schwachstellenprüfung (aktive Erreichbarkeitsprüfung) beschränkt sich auf diesen Mac selbst (127.0.0.1). (4) Die HEAD-Anfrage, die das Fenster „Link-Sicherheitsdiagnose“ direkt an die Ziel-URL sendet, ist im folgenden Absatz beschrieben.
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).
Das wird nicht nur behauptet. Am 2026-08-29 wurde eine laufende 1.4.7-Installation mit tcpdump + Prozesszuordnung (nettop / lsof / eingegrenzter pktap-Mitschnitt) + LuLu über etwa 2 Stunden geprüft, wobei die Sicherheitsstufe auf maximalen Lockdown festgelegt und die Appcast-Prüfung erzwungen wurde. Ergebnis (Stand 1.4.7): Außer der Appcast-Prüfung an lafine.net gab es keinen ausgehenden Verkehr, der RoamSwitch, RoamSwitchHelper oder RoamSwitchMCPServer zugeordnet war; die einzigen Sockets des MCP-Servers gingen an localhost; die Entitlements-Dumps sind leer. Diese Messung betrifft nur 1.4.7. Die seither hinzugekommenen Wege sind in der Tabelle oben aufgeführt; eine Neumessung der aktuellen Version ist geplant.
Vollständige Beschreibung und ein Skript, das jeder ausführen kann, um es zu reproduzieren: audit/RESULTS-2026-08-29.md
Diese Messung stammt von 1.4.7. Seitdem sind folgende Wege hinzugekommen: der Bedrohungs-Feed des Link-Schutzes (1.7.2, Zeile 3 der Tabelle), der VPN-Tunnel (1.7.6, Zeile 6), die Update-Daten des Paket-CVE-Abgleichs (Zeile 4) und die Sensor-Kopplung (Zeile 7). Bei einer Prüfung der aktuellen Version sehen Sie rein empfangende GET-Anfragen an lafine.net (Appcast, Bedrohungs-Feed, Update-Daten); ist ein VPN eingerichtet, sehen Sie außerdem UDP zum eigenen WireGuard-Server des Benutzers (Ziel und Inhalt unter Kontrolle des Benutzers). Der Bedrohungs-Feed verschwindet mit „Automatische Aktualisierung: Aus“, der VPN-Verkehr ohne eingerichtetes VPN (Appcast und die Update-Daten des Paket-CVE-Abgleichs lassen sich nicht abschalten).
§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 lauschenden Socket. Es registriert weder einen Dienst noch lauscht es. Es liest eine Zeile von stdin, gibt eine Zeile auf stdout zurück, und danach beendet der Client den Prozess.
- Es sendet keine Telemetrie. Mit einem externen Host kommuniziert nur run_npm_audit_signatures (npm-Registry), das Opt-in ist und auf dem Mac Pro-exklusiv. run_active_vuln_scan (standardmäßig deaktiviert) prüft nur 127.0.0.1, und get_exposed_ports sendet auf dem Mac nur einen HTTP-GET pro erreichbarem Port an 127.0.0.1, um die Header zu prüfen. Um die MAC-Adresse des Standard-Gateways zu ermitteln, können die Diagnose-Tools einen ICMP-Ping, normalerweise einen (bei nicht auflösbarer MAC einige), an das Gateway im LAN senden.
- 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
| Werkzeug | Was es zurückgibt | Verkehr |
|---|---|---|
| get_security_report | Eine 18-Punkte-Prüfung (FileVault / SIP / Gatekeeper / automatische Updates / XProtect / Firewall / WLAN-Verschlüsselung / ARP / Gateway-ARP-Pinning / SSH-Konfigurationsprüfung / Sudo-NOPASSWD-Prüfung / offene Ports / Guard-Konfiguration und mehr) mit Punktzahl und Empfehlungen je Punkt. Jeder Punkt trägt zudem die entsprechenden NIST-CSF-2.0- und CIS-Controls-v8-Kontroll-IDs (ab 1.10.0). | Nur lokal |
| verify_security_findings | Bewertet Einträge (checkId) aus get_security_report anhand des aktuellen Zustands neu und liefert je Eintrag ein Urteil, nämlich stillPresent (trifft weiterhin zu), resolved (behoben oder konstruktionsbedingt nicht zutreffend) oder inconclusive (nicht feststellbar), dazu einen sprachunabhängigen Begründungscode. Das Tool dient dazu, nach einer Korrektur zu prüfen, ob sie wirklich gewirkt hat. Ein Eintrag, der sich nicht messen ließ, etwa wegen fehlender Berechtigungen, eines nicht verbundenen privilegierten Helpers oder eines nicht erreichbaren Docker, wird nie als sicher gemeldet, sondern als inconclusive. Ohne checkIds werden alle Einträge geprüft (höchstens 50 IDs auf dem Mac und 64 unter Linux; unter Linux ist zusätzlich isServer möglich). Auf dem Mac werden host_firewall, network_stealth_mode, gateway_arp_lock, malware_scanning, dns_threat_guard und usb_zero_trust anhand der App-Einstellungen von RoamSwitch entschieden. Sie geben also diese Einstellungen wieder und messen den tatsächlichen Zustand des Betriebssystems nicht neu. Der Zugriff ist schreibgeschützt, es gibt keine Verbindung zu externen Hosts, keine Reparatur und keine Änderung von Einstellungen. Unter Linux wird auch nichts ins LAN gesendet, das Gateway wird nur aus lokalen Caches gelesen. Auf dem Mac kann zur Ermittlung der Gateway-MAC-Adresse ein ICMP-Ping, normalerweise einer (bei nicht auflösbarer MAC einige), an das Gateway im LAN gehen. | Nur lokal |
| audit_mcp_configs | Liest die MCP-Konfigurationsdateien der KI-Clients (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, Cline, Gemini CLI sowie .mcp.json und ähnliche Dateien in den registrierten Projektordnern) und meldet riskante Einstellungen. Erkannt werden Tools, die ohne Bestätigung je Aufruf automatisch genehmigt werden (auto_approve), Klartext-http://-Server auf einem Nicht-Loopback-Host, ob im Feld url oder als Startargument wie --server http://… angegeben (remote_plain_http), Startbefehle als Shell- oder Interpreter-Einzeiler (shell_wrapper), Starter wie npx / uvx / docker run, die ein nicht festgelegtes Paket oder Image laden (unpinned_package_launcher), docker run mit --privileged oder mit eingebundenem Docker-Socket oder Root-Dateisystem (container_host_access), Umgebungsvariablen, die beim Start zusätzlichen Code laden, etwa LD_PRELOAD oder --require in NODE_OPTIONS (Namen ohne Beachtung der Groß-/Kleinschreibung, Werte werden nie zurückgegeben; code_loading_env), Einträge, die auf HexStrike AI zeigen, ein Angriffstool-Backend ohne Authentifizierung (hexstrike), für Gruppe oder andere beschreibbare Konfigurationsdateien (world_writable_config), der Schalter enableAllProjectMcpServers von Claude Code (auto_trust_project_servers) und eine Konfigurationsdatei, in der ein Server, der von anderen geschriebenen Text liest (Webseiten, Mails, Chats, Issues), neben einem Server steht, der Befehle ausführen oder Dateien ändern kann, also die Kombination, die indirekte Prompt-Injection braucht (anhand bekannter Paketnamen erkannt, die Inhalte der Server-Tools werden nicht gesehen; injection_exposure). Das Tool hat keine Argumente, ist schreibgeschützt und sendet nichts ins Netzwerk. Es gibt keine Env- oder Header-Werte, Argumente oder Geheimnisse zurück, nur Servernamen, den Basisnamen eines Befehls, einen URL-Host und, bei einem einfachen Registry-Namen, den Paket- oder Image-Namen. Nicht lesbare Dateien stehen in unreadableFiles und wurden nicht geprüft. | Keine |
| audit_agent_setup | Liest die Anweisungsdateien und Skills, die KI-Agenten bekommen (CLAUDE.md, commands, agents und skills unter ~/.claude, dazu ~/.codex, ~/.cursor/rules, ~/.gemini, ~/.agents, ~/.openclaw sowie CLAUDE.md, AGENTS.md, .cursorrules und Ähnliches in den registrierten Projektordnern) und OpenClaws openclaw.json und weist auf riskante Inhalte und Einstellungen hin. In Anweisungs- und Skill-Dateien meldet es in unsichtbaren Unicode-Tag-Zeichen versteckte Sätze (hidden_tag_characters), Zeichen ohne Breite und Steuerzeichen für die Schreibrichtung (invisible_characters), Formulierungen, die frühere Anweisungen aufheben oder dem Benutzer etwas verschweigen (override_instruction), Herunterladen-und-Ausführen wie curl … | sh (remote_script_exec), Dekodieren-und-Ausführen (encoded_payload_exec), Verweise auf Schlüssel- und Zugangsdatenspeicher (credential_access) neben einem Upload oder einem Ablage-Dienst (credential_exfil_shape, exfil_endpoint), das Einrichten von Dauerhaftem (persistence_instruction), kompilierten Code in einem Skill (skill_precompiled_code) und für andere beschreibbare Dateien (agent_file_writable). Alles innerhalb eines HTML-Kommentars wird höher eingestuft, weil eine gerenderte Seite es verbirgt. Für OpenClaw werden ausgeschaltete Authentifizierung (openclaw_auth_disabled), eine aus dem Netzwerk erreichbare Bindung (openclaw_wide_bind), ein Token unter 24 Zeichen (openclaw_weak_token), ein Wildcard-Origin (openclaw_origin_wildcard), eingeschaltete dangerously…-Schalter (openclaw_dangerous_flag), eine Proxy-Liste, die jedem vertraut (openclaw_broad_trusted_proxy, openclaw_proxy_trust_loosened), für jeden offene DM- oder Gruppenrichtlinien (openclaw_open_dm), mDNS full (openclaw_mdns_full), ausgeblendete Selbstprüfungs-Befunde (openclaw_audit_suppressed) und lockere Berechtigungen (openclaw_loose_permissions) gemeldet. Jede Regel ist deterministisch: Ein Treffer heißt „ein Mensch sollte diese Zeile lesen“, nicht „bösartig“. Es nimmt keine Argumente, ist schreibgeschützt und sendet nichts ins Netzwerk. Es gibt nie Dateiinhalte oder Geheimnisse zurück (ein Token nur als Länge), sondern nur Regelname, Zeilennummer, URL-Host und Konfigurationsschlüsselpfad. Nicht lesbare Dateien stehen in unreadableFiles und wurden nicht geprüft. | |
| get_exposed_ports | Eine Liste der lauschenden TCP-Ports. Für jeden über „localhost“ hinaus erreichbaren Port erfolgt ein Abgleich mit einer Datenbank bekannter gefährlicher Dienste, und es wird ein einzelner HTTP-GET an 127.0.0.1:port (lokal, geschlossen) gesendet, um CORS und Header zu prüfen. | Nur die Sonde auf 127.0.0.1 |
| get_guard_status | Der 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 Netzwerks | Nur lokal |
| audit_url_safety | Eine 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_help | Eine Volltextsuche in der gebündelten Wissensdatenbank (Funktionsspezifikationen/Einstellungen/Fehlerbehebung/Erklärungen zu Benachrichtigungsmeldungen) | Keine |
| audit_secrets | Erkennt offengelegte API-Schlüssel und private Schlüssel in Text, Dateien oder Verzeichnisbäumen (Treffer werden in der Ausgabe maskiert). | Keine |
| audit_security_logs | Wertet 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). Unter Linux bedeutet eine Zählung von 0 nicht, dass nichts passiert ist, wenn das Journal nicht gelesen werden konnte (zum Beispiel wegen eines Timeouts); journalReadComplete ist dann false und journalError nennt den Grund. | Nur lokal |
| run_active_vuln_scan | Zerstörungsfreie aktive Schwachstellenprüfung, ausschließlich auf 127.0.0.1. Es wird kein anderer Host kontaktiert, aber das Tool sendet Netzwerkanfragen; es ist daher standardmäßig deaktiviert und muss in den Einstellungen per Opt-in aktiviert werden. | Nur 127.0.0.1 (standardmäßig aus) |
| run_package_cve_scan | Gleicht installierte Pakete (Mac: Homebrew / Linux: dpkg, dnf, zypper, pacman) mit einer lokalen CVE-Zuordnung ab. Es findet überhaupt keine Netzwerkkommunikation statt. Unter Linux wird bei nicht lesbarer oder zeitüberschrittener Paketliste nicht „kein Treffer“ gemeldet, sondern complete ist false und incompleteReason nennt den Grund (ein unvollständiges Ergebnis ist kein sauberes Ergebnis). Unter Ubuntu (20.04, 22.04, 24.04, 26.04) werden die Ubuntu-eigenen Daten verwendet und nach Quellpaketname und Quellversion abgeglichen; geprüft werden nur CVEs mit CVSS 7,0 oder höher, für die Ubuntu bereits eine Korrektur veröffentlicht hat, daher bedeutet „kein Treffer“ nicht, dass es keine bekannten CVEs gibt. Das Ergebnis enthält zusätzlich ecosystem und release, jeder Treffer trägt binary (den installierten Binärpaketnamen); Korrekturen, die nur über Ubuntu Pro verfügbar sind, sind mit proOnly markiert. Ubuntu-Derivate (Linux Mint, Pop!_OS und andere) und nicht unterstützte Versionen liefern complete = false mit dem Grund in incompleteReason und werden nicht auf die Debian-Daten umgestellt. | Keine |
| run_package_cve_scan_languages | Gleicht 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_status | Liefert den Inhalt des Malware-Quarantäne-Tresors: ursprünglicher Pfad, erkannter Bedrohungsname, Zeitpunkt und Größe. | Nur lokal |
| get_canary_status | Liefert den Zustand der Ransomware-Köderdateien (Canary) sowie bis zu die 50 jüngsten erkannten Vorfälle. | Nur lokal |
| get_ransomware_recovery_snapshots | Liefert die APFS-Wiederherstellungs-Snapshots (vor dem Schaden, bei Erkennung, manuell), den empfohlenen Snapshot zur Wiederherstellung, den Status des Aufbewahrungsmodus und das Snapshot-Intervall. Ein Erkennungs-Snapshot kann bereits verschlüsselte Dateien enthalten. Nur Pro. | Nur lokal |
| search_exec_events | Durchsucht die Aufzeichnung der Prozessstarts (eslogger) nach Pfad, Argumenten oder Signatur-ID und liefert den Zustand des Recorders sowie ob die Aufzeichnung lesbar ist. Nur Pro. | Nur lokal |
| get_process_tree | Stellt aus der Aufzeichnung die Vorfahren und Nachfahren eines Prozesses zusammen. Nur Pro. | Nur lokal |
| get_notification_history | Gibt 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_incidents | Liefert 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_ssh_guard_incidents | Gibt Zustand und Verlauf des SSH-Brute-Force-Schutzes zurück: ob er sperrt oder nur erkennt (zum Beispiel weil ein anderes Werkzeug sshd bereits schützt), die aktuell gesperrten Quellen mit Restzeit und bis zu 200 jüngste Einträge (eine Quelle wurde gesperrt, nur erkannt, oder eine Anmeldung gelang nach einer Serie von Fehlversuchen derselben Quelle). Die versuchten Benutzernamen werden unter Linux nicht gespeichert (nur die Anzahl) und unter Mac bereinigt mit bis zu 5 Namen zurückgegeben. Der Mac liefert zusätzlich die letzten SSH-Anmeldungen (Quelle, Benutzer, Methode, Schlüssel-Fingerabdruck). Schreibgeschützt: Kein MCP-Tool hebt eine Sperre auf. Unter Linux kann nur root die Sperrliste lesen; ein Aufruf ohne root liefert nur die Anzahl. Linux: die Server Edition sowie die Client Edition, solange sshd läuft. Mac: nur Pro. | Nur lokal |
| get_runtime_threat_status | Gibt 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 |
| get_ransomware_entropy_guard_status | Gibt zurück, ob die allgemeine entropiebasierte Ransomware-Erkennung aktiviert ist, sowie ihre jüngsten Entropie-Burst-Vorfälle. | Nur lokal |
| get_honeytoken_status | Gibt zurück, ob der Anmeldedaten-Honeytoken-Guard aktiviert ist, sowie seine jüngsten Zugriffserkennungsereignisse. | Nur lokal |
| get_browser_credential_watch_status | Gibt zurück, ob die Überwachung des Browser-Anmeldedatenzugriffs aktiviert ist, sowie ihre jüngsten Zugriffserkennungsereignisse. | Nur lokal |
| get_forensic_evidence_bundles | Gibt die Liste der forensischen Beweispakete zurück (Prozessliste, Netzwerkverbindungen, geänderte Dateien und Ähnliches), die beim Auslösen eines Notfall-Air-Gap gespeichert wurden. | Nur lokal |
| get_vulnerability_scan_history | Gibt das zuletzt erfasste Ergebnis und die verstrichenen Tage (pass_age) für jede Prüfung zurück, die run_active_vuln_scan aufgezeichnet hat. | Nur lokal |
Auch das Feld instructions in der initialize-Antwort besagt eindeutig:
„Cannot change security level, isolate ports, or eject devices“ und teilt dem
LLM auf Client-Seite die Grenzen seiner Möglichkeiten mit. Die MCP-Ressourcen
(roamswitch://docs/*) sind ebenfalls schreibgeschützte Markdown-Dokumente.
1.10.0 fügt vier Triage-Skill-Dokumente im agentskills.io-Format hinzu
(roamswitch://skills/*, nur auf Englisch, bewusst).
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.
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
invalidSignaturezurü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
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)
- Führen Sie
xcodebuild archiveaus (Release, manuelle Signatur, Entwickler-ID-Anwendung). - Export mit
-exportArchivealsmethod: developer-id. - Führen Sie nach
notarytool submit --waitstapler staplein der .app aus. - Überprüfen Sie mit
spctl -a -t exec -vv. - 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).
- 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)
| Schlüssel | Wert |
|---|---|
| SUFeedURL | https://lafine.net/updates/appcast.xml |
| SUPublicEDKey | CNxzwijMzMCJzliId76Yl88S/9np6t/xg/zQ9YbYzHs= |
| SUEnableAutomaticChecks | wahr |
| SUScheduledCheckInterval | 86400 |
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.
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.
- Man-in-the-Middle-Angriffe (ARP/NDP-Spoofing). Seit 1.7.6 wird dies mehrschichtig abgedeckt: (1) VPN-Tunnel + Kill-Switch (§5, die Hauptverteidigung, unabhängig von der Integrität von L2), (2) vorbeugende Fixierung des Gateways per ARP/NDP in nicht vertrauenswürdigen Netzwerken (§5) und (3) Spoofing-Erkennung mit Notfall-Air-Gap (im Nachhinein). VPN-Tunnel und Gateway-Fixierung sind Pro-Funktionen und standardmäßig aus. Die Spoofing-Erkennung ist standardmäßig an, und der Notfall-Air-Gap ist nach der Aktivierung von Pro standardmäßig an.
- Auffinden von Entwicklungsservern und Datenbanken (Redis, MongoDB, Elasticsearch usw.), die auf
0.0.0.0ohne 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.sockeingebunden (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 | Wie 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 |
Hardened Runtime ist aktiviert, und die App erhält keine unnötigen Berechtigungen. Das Senden über das Netzwerk beschränkt sich auf die Wege in der Tabelle von §7 (und die unter dieser Tabelle beschriebenen, vom Benutzer ausgelösten und standardmäßig deaktivierten Funktionen). Ein Entitlement für Netzwerkversand wird nicht deklariert; da die App aber nicht in der Sandbox läuft, verbietet das allein keine Kommunikation (Messungen am Ende von §7). Eine Prüfung durch Dritte ist geplant. |
| 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 gerätespezifische Kennung (nur der Standard-User-Agent). 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
Entitlements (Bestätigung, dass kein Entitlement für Netzwerkversand deklariert ist; da die App nicht in der Sandbox läuft, verbietet das allein keine Kommunikation)
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 außerhalb der Wege in der Tabelle entsteht
sudo tcpdump -i any -n 'host not 127.0.0.1' and 'not port 53'
# Kein Traffic außer den Wegen der Tabelle (Lizenzaktivierung, Update-Prüfungen, signierte Update-Daten, ClamAV-Updates usw.)
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 gerätespezifische Kennung gesendet (nur der Standard-User-Agent). 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 Tool-Definitionen 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}'