Sicherheits-Audit — Juni 2026 — Runde 2
Code-Security-Review
NetMon Roots v1.1.14
Zweites automatisiertes Multi-Agenten-Security-Review auf Basis von
Claude Sonnet 4.6. Erstmalig einbezogen: das neue Radio-Modul
(radio_controller.py, 5 531 Zeilen),
chad_controller.py, fun_controller.py,
ai_analysis_service.py, lang_service.py,
network_helpers.py, neue UI-Tabs sowie alle seit Runde 1
refaktorierten Bereiche (82 Proxy-Methoden entfernt,
Security-Monitoring-Controller gesplittet).
Umfang & Methodik
Die Analyse folgte demselben dreistufigen Prozess wie Runde 1, ergänzt um eine dritte manuelle Verifikationsrunde für den Radio-Kandidaten K1. Schwerpunkt: alle Module, die in Runde 1 noch nicht im Scope waren — insbesondere das komplette Radio-Modul (5 531 Zeilen, externe API-Anbindung, mpv-Subprocess, ffmpeg-Recording) sowie neu hinzugekommene Services und UI-Tabs. Zusätzlich wurden alle seit Runde 1 geänderten Dateien auf Sicherheitsregressionen geprüft.
Phase 1 — Reconnaissance
Lesen aller neuen und geänderten Module; Fokus auf externe API-Anbindungen, Subprocess-Aufrufe mit externen Daten, URL-Handling, Datei-Operationen mit Nutzereingabe, eval/exec, Deserialisierung.
Phase 2 — Kandidaten-Analyse
Datenflussketten von externen Quellen (API-Antworten, Nutzerdialogen)
bis zu sensitiven Operationen nachverfolgt. Besonderes Augenmerk:
URL-Schemata an mpv, ffmpeg,
urllib.request und webbrowser.open().
Phase 3 — False-Positive-Filter
Jeder Kandidat in einem unabhängigen Agenten re-analysiert.
Ausschluss: DoS, Single-User-Desktop ohne Fremd-Input,
stdout/stderr=DEVNULL + Re-Encoding verhindert Exfil,
Browser-Sandbox, bestehende Schema-Allowlist-Validierung.
Phase 4 — Manuelle Verifikation (K1)
Zusätzliche Nachprüfung des Radio-Kandidaten durch direktes
Lesen der Funktionskette:
normalize_station_entry() →
_normalize_station_stream_url() →
ALLOWED_RADIO_STREAM_SCHEMES. Kandidat widerlegt.
Neu analysierte Module (Runde 2)
| Datei / Modul | Fokus | Ergebnis |
|---|---|---|
netmon/features/radio_controller.py |
mpv-Subprocess, ffmpeg-Recording, radio-browser.info API,
urllib.request ICY-Fetch; URL-Schema-Validierung via
_normalize_station_stream_url() |
Kein Finding |
netmon/features/chad_controller.py |
KI-Integration, getattr-Zugriffsmuster, Datei-Import | Kein Finding |
netmon/features/fun_controller.py |
Subprocess-Aufrufe, Paketprüfung | Kein Finding |
netmon/features/speedtest_controller.py |
Speedtest-Subprocess, Ergebnis-Parsing | Kein Finding |
netmon/features/dot_controller.py |
Dropin-Generierung, systemd-Konfiguration | Kein Finding |
netmon/features/security_audit_controller.py |
Lynis/rkhunter-Aufrufe, Startup-Guard-Baseline-Lesen | Kein Finding |
netmon/services/ai_analysis_service.py |
KI-Analyse-Pipeline, Datenübertragung | Kein Finding |
netmon/services/lang_service.py |
Lokalisierung, JSON-Ladevorgang | Kein Finding |
netmon/services/network_helpers.py |
Netzwerk-Hilfsfunktionen, IP-Parsing | Kein Finding |
netmon/core/coordinator.py |
Zentraler Koordinator, Modul-Init | Kein Finding |
netmon/core/state.py |
Globaler Zustand, Attributzugriff | Kein Finding |
netmon/ui/tabs/radio_tab.py |
Radio-UI, Benutzerinteraktion, Event-Handling | Kein Finding |
netmon/ui/tabs/cleanup_assistant_tab.py |
System-Cleanup-UI, Dateioperationen | Kein Finding |
netmon/ui/tabs/download_scan_tab.py |
Download-Scan, ClamAV-Integration | Kein Finding |
netmon/ui/tabs/fun_tab.py |
Fun-Modul-UI | Kein Finding |
netmon/ui/tabs/chad_settings_tab.py |
KI-Einstellungen, API-Key-Handling | Kein Finding |
scripts/refactor_safety.py |
AST-Analyse, Caller-Check, Read-Only-Tool | Kein Finding |
netmon/app.py (Refaktorierung) |
82 Proxy-Methoden entfernt — Angriffsflächenreduktion | Keine Regression |
Bewertete Kandidaten (alle ausgeschlossen)
Vier Muster wurden im ersten Analysedurchgang identifiziert und in parallelen, unabhängigen Filter-Agenten sowie einer abschließenden manuellen Verifikation re-analysiert. Kein Kandidat überschritt die Konfidenz-Schwelle von 8/10.
K1 — Radio-URL an mpv / urllib.request — manuell widerlegt
Konfidenz 8/10 → FP AusgeschlossenDatei: netmon/features/radio_controller.py
Initiale Bewertung (Phase 2): Radio-Stations-URLs aus dem
externen radio-browser.info-API gelangen ohne
Schema-Validierung an mpv (Zeile 4835) und
urllib.request.urlopen() (Zeile 3150). Erstes
Filter-Ergebnis: Konfidenz 8/10 — bestätigt.
Manuelle Nachprüfung: Beim direkten Lesen
der Aufrufkette wurde _normalize_station_stream_url()
(Zeile 298–309) identifiziert, die bei der automatischen
Analyse übersehen wurde:
ALLOWED_RADIO_STREAM_SCHEMES = {"http", "https", "rtsp", "rtmp"} # Zeile 103
def _normalize_station_stream_url(value) -> str: # Zeile 298
parsed = urllib.parse.urlparse(url)
scheme = str(parsed.scheme or "").strip().lower()
if scheme not in ALLOWED_RADIO_STREAM_SCHEMES:
return "" # nicht erlaubte Schemata werden abgelehnt
return url
def normalize_station_entry(entry, ...): # Zeile 312
url = _normalize_station_stream_url(...) # Zeile 317
if not name or not url:
return None # Station wird verworfen
Jede URL durchläuft _normalize_station_stream_url()
bevor sie ins Station-Dict übernommen wird. Stationen mit
nicht-erlaubten Schemata (file://, lavfi://,
etc.) werden als None verworfen und nie gespeichert.
_fetch_icy_stream_title() erhält ausschließlich
vorvalidierte URLs aus dem Station-Dict.
file://, lavfi:// und
alle anderen nicht-erlaubten Schemata werden in
_normalize_station_stream_url() abgelehnt —
bevor die URL mpv oder urllib.request
erreicht. Kein SSRF-Pfad, kein Angriffspfad. False Positive.
K2 — webbrowser.open mit nicht validierter API-URL
Konfidenz 3/10 AusgeschlossenDatei: netmon/features/radio_controller.py, Zeile 5197
webbrowser.open(url, new=2) wird mit dem
homepage-Feld aus der API-Antwort ohne Schema-Validierung
aufgerufen. Auf Linux ruft webbrowser.open() intern
xdg-open auf. Theoretisch könnte eine
file://-URL übergeben werden.
file://-URLs. Eine
geöffnete lokale Datei wird im eigenen Browser des Nutzers
angezeigt — keine Exfiltration möglich.
javascript:-URIs werden als Top-Level-URL nicht ausgeführt.
Kein exploitierbarer Angriffspfad. Konfidenz 3/10 → ausgeschlossen.
K3 — ffmpeg -i mit nicht validierter API-URL
Konfidenz FP
Ausgeschlossen
Datei: netmon/features/radio_controller.py, Zeile 2160
_recording_command(stream_url, output_path) übergibt
die Station-URL als ffmpeg -i <url>-Argument.
ffmpeg unterstützt Protokolle wie file://,
concat://, lavfi:// u. a.
_normalize_station_stream_url() gegen
ALLOWED_RADIO_STREAM_SCHEMES validiert.
(2) Selbst ohne diese Prüfung: stdin,
stdout und stderr sind nach
subprocess.DEVNULL umgeleitet; die Ausgabe wird durch
den libmp3lame-Codec trancodiert. Kein Exfiltrationspfad.
K4 — Dateilese-Operation via Startup-Guard-Baseline
Konfidenz FP AusgeschlossenDatei: netmon/features/security_audit_controller.py, Zeilen 1173–1184
format_startup_guard_entry_details() öffnet und liest
beliebige Dateipfade aus Startup-Guard-Einträgen, die aus einer
nutzerschreibbaren JSON-Baseline-Datei stammen können.
open()
ohne sudo erreicht. Keine zusätzlichen
Fähigkeiten erworben. Ausgeschlossen.
Sicherheitsverbesserungen seit Runde 1
Die folgenden Hardening-Empfehlungen aus Audit Runde 1 wurden im aktuellen Codestand umgesetzt.
ClamAV Tempdir: Symlink-Schutz implementiert — clamav_controller.py
Runde 1 empfahl, os.makedirs(exist_ok=True) durch eine
Sequenz zu ersetzen, die Symlinks vor dem Anlegen des Verzeichnisses
prüft und ablehnt (Punkt 4). Umgesetzt als
_safe_makedirs_no_symlink(path) (Zeile 71):
prüft via os.lstat(), ob der Zielpfad ein Symlink ist,
und wirft bei positivem Befund einen RuntimeError.
Empfehlung geschlossen.
URL-Schema-Validierung im Radio-Modul — radio_controller.py
Das Radio-Modul enthält bereits eine vollständige
Schema-Allowlist-Validierung:
ALLOWED_RADIO_STREAM_SCHEMES = {“http”, “https”, “rtsp”, “rtmp”}
(Zeile 103), durchgesetzt durch
_normalize_station_stream_url() (Zeile 298–309)
via urllib.parse.urlparse().
Nicht-erlaubte Schemata werden vor der Speicherung
im Station-Dict abgelehnt — mpv und urllib.request empfangen
ausschließlich validierte URLs.
Angriffsflächenreduktion: 82 Proxy-Methoden aus app.py entfernt
Im Zuge der God-Object-Extraktion wurden 82 Proxy-Methoden aus
app.py gelöscht, deren Controller-Gegenstücke
in netmon/features/ bereits vorhanden waren. Alle Methoden
wurden vorab per refactor_safety.py auf Null-Aufrufer
verifiziert (AST-Check + grep). Commit 920cfc9b.
Hardening-Empfehlungen (keine kritischen Bugs)
Die folgenden Punkte sind keine Sicherheitslücken, sondern Defense-in-Depth-Maßnahmen aus Runde 1, die noch offen sind.
-
Git-Subcommand-Allowlist in
agent/runner.py: Sobald LLM-Output inrun_command()fließt, eine explizite Subcommand-Allowlist ergänzen (status,diff,log,show). Derzeit latentes Architektur-Risiko (Runde 1, Punkt 1). -
IP-Validierung für WireGuard-Endpoints:
parse_vpn_endpoint()sollte den Host-Teil mitipaddress.ip_address()validieren, bevor er in UFW-Kommandos eingebettet wird (Runde 1, Punkt 2). -
Pfadprüfung in
image_to_data_url(): Optional: Dateipfad zusätzlich auf das Benutzer-Homeverzeichnis einschränken. Aktuell kein ausnutzbarer Angriffspfad vorhanden (Runde 1, Punkt 3). -
Schema-Validierung für
homepage-URLs im Radio-Modul:webbrowser.open(station["homepage"])validiert das Schema nicht. Obwohl kein direkter Exploit-Pfad besteht (Browser-Sandbox), wäre eine analoge Allowlist-Prüfung vor demwebbrowser.open()-Aufruf defensive Best Practice. -
Shell-Quoting in Repository-Guard-Snippets:
URI- und Pfadwerte in
get_repository_guard_quick_action_snippet()mitshlex.quote()maskieren (Runde 1, Punkt 5). -
os.path.realpath()im Roots-Baseline-Guard:_normalize_guard_path_pattern()sollteos.path.abspathdurchos.path.realpath()ersetzen, um Symlinks vor dem fnmatch-Check aufzulösen (Runde 1, Punkt 6).
Geprüfte Sicherheitskategorien
| Kategorie | Geprüft | Ergebnis |
|---|---|---|
| Command Injection (subprocess, shell=True) | Ja | Kein Finding |
| Path Traversal (Dateioperationen mit Nutzereingabe) | Ja | Kein Finding |
| Privilege Escalation (sudo-Nutzung, Argument-Injektion) | Ja | Kein Finding |
| Unsichere Deserialisierung (pickle, yaml.load) | Ja | Kein Finding |
| Eval/Exec mit Nutzereingabe | Ja | Kein Finding |
| Hardcoded Credentials / API-Keys | Ja | Kein Finding |
| Authentication Bypass / Privilege Escalation | Ja | Kein Finding |
| Sensitive Data Exposure (PII in Logs) | Ja | Kein Finding |
| Externe API-Aufrufe mit unkontrollierten Daten | Ja | Kein Finding |
| SSRF via urllib.request / externe URL-Weitergabe | Ja | Kein Finding |
| Kryptographische Schwachstellen | Ja | Kein Finding |
| Symlink-Angriffe auf privilegierte Dateioperationen | Ja | Kein Finding |
| Clipboard-Injection / Snippet-Generierung | Ja | Kein Finding |
| URL-Schema-Validierung an Media-Subprocess | Ja | Kein Finding |
Auditor: Claude Sonnet 4.6 (Anthropic) —
Automatisiertes Multi-Agenten-Sicherheits-Review + manuelle Verifikation
Projektverantwortlicher: Sven Fröhlich
Datum: 28. Juni 2026
Analysierter Codestand:
e334324a … 920cfc9b
+ Arbeitsstand (unstaged), gesamt 100+ Dateien — Runde 2
Methode: Statische Code-Analyse + manuelle Datenfluss-Verifikation
— kein Laufzeit-Penetrationstest
Haftungsausschluss: Dieses Audit ersetzt keinen professionellen
Penetrationstest durch eine zertifizierte Sicherheitsfirma. Die Analyse
beschränkt sich auf den angegebenen Codestand. Nicht erfasst werden:
Laufzeitverhalten, abhängige Systembibliotheken,
Netzwerkkonfiguration und soziale Angriffsvektoren.
Zur Downloadseite • Aktuelles • Dokumentation • Legal / Lizenz