NETMON ROOTS MONITOR. CONTROL. UNDERSTAND. BACK TO THE ROOTS.
DE

Sicherheits-Audit — Juni 2026 — Runde 4

Code-Security-Review
NetMon Roots v1.1.15

Viertes automatisiertes Multi-Agenten-Security-Review auf Basis von Claude Sonnet 4.6. Schwerpunkt dieser Runde: alle seit Runde 3 geänderten Module — darunter der vollständig überarbeitete vpn_controller.py, der neue Mountpoint-Guard in hdd_controller.py, die CWD-Bereinigung in linux_help_controller.py, das Bug-Fix-Paket aus lock.py, command.py, dns_control_service.py und startup_guard_service.py sowie die Aufspaltung des Security-Monitoring-Controllers in _core.py / _scanning.py. Insgesamt 40+ geänderte Dateien, 20 davon mit sicherheitsrelevantem Fokus analysiert.

← Runde 3 (7 Kandidaten, 3 Findings — alle geschlossen)
PDF herunterladen Kandidaten Hardening

Keine kritischen Schwachstellen gefunden

Der einzige identifizierte Kandidat (K1 — WireGuard-Import mit PostUp/PreDown-Hooks) wurde in einer unabhängigen Filter-Runde mit Konfidenz 3/10 als False Positive ausgeschlossen — kein Privilege-Boundary-Crossing, da der Code bereits einen expliziten Nutzerhinweis via _warn_wireguard_import_hooks() anzeigt. Alle sechs seit Runde 1 offenen Hardening-Empfehlungen wurden in diesem Codestand zusätzlich als vollständig umgesetzt verifiziert. Der Codestand v1.1.15 enthält keine ausnutzbaren Sicherheitslücken mit echtem Angriffspfad.

Datum
29. Juni 2026
Analysierte Version
v1.1.15 — Runde 4
Geänderte Dateien
40+
Sicherheitsfokus-Module
20
Kritische Findings
0
Bewertete Kandidaten
1
Konfidenz-Schwelle
8 / 10
Analysewerkzeug
Claude Sonnet 4.6

Umfang & Methodik

Die Analyse folgte demselben vierstufigen Prozess wie Runde 3. Schwerpunkt: alle Module, die seit Runde 3 neu hinzugekommen oder inhaltlich geändert wurden — insbesondere das vollständig refaktorierte VPN-Modul, der neue HDD-Mountpoint-Guard, die Bereinigung des linux_help-Controllers und das zentrale Bug-Fix-Paket aus Commit 363d64f5. Zusätzlich wurden alle aus Runde 3 als offen gemeldeten Hardening-Empfehlungen auf Umsetzungsstand geprüft.

Phase 1 — Reconnaissance

Lesen aller 40+ geänderten Module; Fokus auf externe Subprocess-Aufrufe mit Nutzerdaten, sudo-Einbettung, URL-Handling, Dateioperationen mit unkontrollierten Pfaden, eval/exec, unsichere Deserialisierung und Privilegienübergänge.

Phase 2 — Kandidaten-Analyse

Datenflussketten von externen Quellen (WireGuard-Konfig-Dateien, API-Antworten, Nutzerdialogen, Dateisystem) bis zu sensitiven Operationen (sudo install, wg-quick up, subprocess.Popen) vollständig nachverfolgt.

Phase 3 — False-Positive-Filter

K1 in einem unabhängigen Agenten re-analysiert: vollständiger Quelltext von vpn_controller.py gelesen, exakter Code der Import-Funktion lokalisiert. Ausschluss: kein Privilege-Boundary-Crossing, explizite Nutzerinteraktion, bestehende sudo-Rechte.

Phase 4 — R3-Nachverfolgung

Alle 3 Findings aus Runde 3 auf Umsetzungsstand geprüft: rkhunter_manager.py (K1 R3), fun_controller.py (K2 R3) und agent/runner.py (K3 R3) — alle drei im aktuellen Codestand geschlossen bestätigt.

Sicherheitsfokus-Module (Runde 4)

Datei / Modul Fokus Ergebnis
netmon/features/vpn_controller.py WireGuard-Import (sudo install), wg-quick up/down, Interface-Name-Validierung, Filename-Regex, Pfad-Confinement K1 → FP
netmon/features/hdd_controller.py Mountpoint-Validierung via realpath() + _SAFE_MOUNT_BASES, LUKS-Passphrase via stdin, sudo mount/umount Kein Finding
netmon/features/linux_help_controller.py CSV/XLSX-Suchpfade nach CWD-Entfernung, kein Subprocess Kein Finding
netmon/core/lock.py EPERM-Behandlung bei os.kill(), Instanz-Lock-Datei Kein Finding
netmon/core/command.py Generischer run_cmd-Wrapper, shell=False, sudo -S -v-Passphrase via input= Kein Finding
netmon/services/dns_control_service.py nmcli con mod <con> via List-Form, DNS-Token-Validierung (Falsy-Zero-Fix) Kein Finding
netmon/services/startup_guard_service.py SHA-256-Hashing, neue Dateien als “new”, kein Subprocess Kein Finding
netmon/features/security_monitoring_controller/_core.py Event-System, Baseline-Verwaltung, Shared Helpers, kein Subprocess Kein Finding
netmon/features/security_monitoring_controller/_scanning.py Geräte-/Integritäts-Scanning, kein Subprocess, Dateihash-Vergleich Kein Finding
netmon/features/firewall_controller.py UFW-Integration, Port-Regex + ipaddress-Validierung, shell=False Kein Finding
netmon/features/clamav_controller.py ClamAV-Subprocess, _safe_makedirs_no_symlink(), realpath()-Pfad Kein Finding
netmon/features/radio_controller.py mpv/ffmpeg-Subprocess, ALLOWED_RADIO_STREAM_SCHEMES, URL-Schema-Allowlist Kein Finding
netmon/features/security_audit_controller.py Lynis/rkhunter-Aufrufe, Startup-Guard-Baseline-Lesen Kein Finding
netmon/features/packet_capture_controller.py tshark-Subprocess, Interface-Name aus ip link, shell=False Kein Finding
netmon/features/dns_controller.py DNS-Proxy-Delegation, kein direkter Subprocess Kein Finding
netmon/features/chad_controller.py KI-Integration, getattr-Fix, kein Subprocess Kein Finding
netmon/features/dot_controller.py DNS-Dropin via sudo install, Pfad hardcoded Kein Finding
netmon/services/path_guard_service.py PATH-Analyse, read-only, kein Subprocess Kein Finding
agent/runner.py REPO_ROOT-Fix, Subprocess-Allowlist, Pfad-Confinement (K3 R3 geschlossen) Kein Finding
agent/tools.py Dateilesen mit relative_to(REPO_ROOT)-Guard Kein Finding
netmon/app.py (Refaktorierung) 82 Proxy-Methoden entfernt — Angriffsflächenreduktion, keine Regression Keine Regression
scripts/refactor_safety.py AST-Analyse, Caller-Check, Read-Only-Werkzeug Kein Finding

Bewerteter Kandidat (ausgeschlossen)

Ein Muster wurde im ersten Analysedurchgang identifiziert und in einem unabhängigen Filter-Agenten (vollständiger Quelltext gelesen) re-analysiert. Der Kandidat überschritt die Konfidenz-Schwelle von 8/10 nicht.

K1 — WireGuard-Konfig-Import: PostUp/PreDown-Hooks ohne Inhaltsprüfung

Konfidenz 7/10 → 3/10 → FP Ausgeschlossen

Datei: netmon/features/vpn_controller.pyimport_wg_profiles_from_folder()

Initiale Bewertung (Phase 2): WireGuard-.conf-Dateien werden per sudo -n install -m 600 <src> /etc/wireguard/<name>.conf ohne Inhaltskontrolle in das System übernommen. Da wg-quick up die Direktiven PostUp, PreDown, PostDown und PreUp als Root-Shell-Befehle ausführt, würde eine präparierte .conf-Datei bei Profil-Aktivierung beliebigen Code als root ausführen können. Erstes Filter-Ergebnis: Konfidenz 7/10.

Vorhandene Schutzmaßnahmen:

  • Dateiname via re.fullmatch(r"[A-Za-z0-9_.-]+", name) validiert
  • Zielpfad via os.path.commonpath() auf /etc/wireguard/ begrenzt
  • wg_profile_path() normalisiert den Pfad zusätzlich via os.path.realpath()
for src in selected_files:
    base = os.path.basename(src)
    name = base[:-5] if base.endswith(".conf") else base
    if not re.match(r"^[A-Za-z0-9_.-]+$", name):   # Dateiname validiert
        skipped += 1; continue
    target = app._wg_profile_path(name)             # Pfad-Confinement
    if not target:
        skipped += 1; continue
    rc_cp, out_cp = run_cmd(
        ["sudo", "-n", "install", "-m", "600", src, target], timeout=10
    )
    # Dateiinhalt wird nicht geprueft — PostUp/PreDown-Hooks werden uebernommen

Unabhängige Nachprüfung: Nach vollständigem Lesen von vpn_controller.py wurde der tatsächliche Angriffsweg bewertet.

Filterentscheid: Kein Privilege-Boundary-Crossing auf einem Single-User-Desktop. Der Nutzer initiiert den Import ausschließlich über einen nativen Datei-Dialog (filedialog.askopenfilenames()) und wählt die .conf-Datei bewusst aus. WireGuard-Hook-Direktiven sind ein dokumentiertes und erwartetes Feature des Protokolls — kein versteckter Angriffspfad. Ein externer Angreifer müsste entweder bereits Schreibzugriff auf das Dateisystem besitzen (= volle Kompromittierung) oder den Nutzer durch Social Engineering zur gezielten Dateiauswahl bringen (Supply-Chain-Problem, keine Code-Schwachstelle). Die Anwendung setzt bereits sudo-Rechte voraus (ensure_sudo_session() gate); der Nutzer hat dieselben Rechte, die wg-quick benötigt. Konfidenz nach Filterrunde: 3/10 → False Positive.

Sicherheitsverbesserungen seit Runde 3

Die folgenden sicherheitsrelevanten Änderungen wurden seit Audit Runde 3 im Codestand implementiert.

🔒

HDD Mountpoint-Validierung — hdd_controller.py — Security Fix

Commit 0431faf8: _slot_mountpoint() kanonisiert den Pfad jetzt via os.path.realpath() (verhindert ../-Tricks) und prüft anschließend gegen _SAFE_MOUNT_BASES = ("/mnt/", "/media/", "/run/media/"). Ungültige Mountpoints fallen auf den sicheren Default /mnt/<device-basename> zurück. Zuvor konnte ein Angreifer mit Schreibzugriff auf die HDD-Slot-Konfiguration einen beliebigen Mountpoint (z. B. /etc) setzen, der dann per sudo mount mit einem präparierten Filesystem überschrieben werden konnte → Privilege Escalation.

CWD-Entfernung aus CSV-Suchpfaden — linux_help_controller.py

Commit 363d64f5: os.getcwd()-Fallback wurde aus den CSV-Suchpfaden entfernt. Zuvor konnte ein Angreifer eine manipulierte linux-befehle.csv in einem world-writable Arbeitsverzeichnis ablegen und damit Command-Injection-kompatible Inhalte in das Linux-Hilfe-Modul einschleusen (Command-Injection-Risiko beseitigt).

EPERM-Behandlung in lock.py korrigiert

Commit 363d64f5: os.kill(pid, 0) wirft PermissionError (EPERM), wenn der Prozess läuft, aber einem anderen Benutzer gehört. Dieser Fall wurde bisher fälschlich als veralteter Lock gewertet, wodurch eine zweite Instanz gestartet werden konnte. Fix: EPERM → Prozess läuft, Lock ist gültig.

REPO_ROOT dynamisch aus __file__agent/runner.py

Commit 363d64f5: Hardcoded Pfad /workspaces/dev-lab (Codespaces-Pfad) durch Path(__file__).resolve().parent.parent ersetzt. Verhindert, dass der Agent-Runner außerhalb der Codespaces-Umgebung alle Befehle mit falschem CWD ausführt (Funktionskorrektheit + Sicherheitsrelevanz: REPO_ROOT-Confinement war wirkunslos).

DNS-Token-Validierung: Falsy-Zero-Falle — dns_control_service.py

Commit 363d64f5: token.count(".") wurde zu token.count(".") > 0 geändert. Das alte Muster wertete den Ausdruck als falsy, wenn genau 0 Punkte vorhanden waren, und konnte damit numerische IP-Tokens wie 192 (ohne Punkt) als gültig durchlassen.

Angriffsflächenreduktion: 82 Proxy-Methoden aus app.py entfernt

Commits a279e38c + 920cfc9b: Insgesamt 101 tote bzw. Proxy-Methoden aus app.py gelöscht. Alle Methoden wurden vorab per scripts/refactor_safety.py auf Null-Aufrufer verifiziert (AST-Check + grep). Die God-Object-Reduktion verkleinert die effektive Angriffsfläche und macht den Kontrollfluß transparenter.

R3-Findings bestätigt geschlossen — rkhunter, fun_controller, agent/runner

Alle 3 aus Runde 3 bestätigten Findings wurden im aktuellen Codestand verifiziert: K1 R3 (rkhunter_manager.py PATH-Hijacking) via TRUSTED_WEB_CMD_PREFIXES geschlossen; K2 R3 (fun_controller.py Pfad-Confinement) via realpath()-Check auf fun_games_dir geschlossen; K3 R3 (agent/runner.py Pfad-Allowlist) via REPO_ROOT-Confinement für black/ruff/pytest/ls geschlossen.

Hardening-Empfehlungen — alle geschlossen

Sämtliche seit Runde 1 offenen Defense-in-Depth-Empfehlungen wurden im aktuellen Codestand v1.1.15 vollständig umgesetzt und per direktem Quelltext-Check verifiziert.

IP-Validierung für WireGuard-Endpoints — vpn_controller.py:2479

parse_vpn_endpoint() verwendet ipaddress.ip_address(host) zur strikten Host-Validierung. Nicht-IP-Hostnamen werden übersprungen und via _warn_non_ip_endpoint_once() protokolliert. Der Host-Teil erreicht UFW-Kommandos nur als validiertes endpoint_ip.compressed. (Runde 1, Punkt 2 — geschlossen)

Schema-Validierung homepage-URLs im Radio-Modul — radio_controller.py:106+315

ALLOWED_RADIO_HOMEPAGE_SCHEMES = {"http", "https"} (Zeile 106). Die Funktion _normalize_station_homepage_url() (Zeilen 315–326) validiert jede Homepage-URL via urllib.parse.urlparse() gegen diese Allowlist und wird in open_selected_station_homepage() (Zeile 5231) aufgerufen — bevor webbrowser.open() die URL erhält. (Runde 2, Punkt 4 — geschlossen)

Shell-Quoting in Repository-Guard-Snippets — repository_guard_controller.py:799–802

get_repository_guard_quick_action_snippet() maskiert alle eingebetteten Werte mit shlex.quote(): quoted_uri, quoted_path, quoted_host und quoted_keyring_path. (Runde 1, Punkt 5 — geschlossen)

realpath() im Roots-Baseline-Guard — roots_baseline_guard_controller.py:123

_normalize_guard_path_pattern() verwendet os.path.realpath(os.path.expanduser(raw)) — Symlinks werden vollständig aufgelöst, bevor fnmatch-Vergleiche und Allowlist-Prüfungen greifen. (Runde 1, Punkt 6 — geschlossen)

Pfadprüfung in image_to_data_url()ai_online_service.py:35–39

resolved.relative_to(home_dir) stellt sicher, dass der Bildpfad innerhalb des Benutzer-Homeverzeichnisses liegt. Zusätzlich wird resolve(strict=True) verwendet (Symlinks aufgelöst, Existenz sichergestellt) und die Dateiendung gegen eine Allowlist erlaubter Bildformate geprüft. (Runde 1, Punkt 3 — geschlossen)

WireGuard-Import: Hook-Hinweis — vpn_controller.py:141+3229+3328+3363

_warn_wireguard_import_hooks() (Zeile 141) scannt jede ausgewählte .conf-Datei vor dem Import auf PreUp/PostUp/PreDown/PostDown-Direktiven und zeigt bei Fund einen expliziten Nutzerhinweis an (messagebox mit Option zum Abbruch). Die Funktion wird an drei Import-Einstiegspunkten aufgerufen (Zeilen 3229, 3328, 3363). (K1-FP Defense-in-Depth — geschlossen)

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 mit unkontrollierten Argumenten) Ja Kein Finding
Argument Injection (list-form subprocess mit externen Daten) Ja Kein Finding
Unsichere Deserialisierung (pickle, yaml.load, eval) Ja Kein Finding
Eval/Exec mit Nutzereingabe Ja Kein Finding
Hardcoded Credentials / API-Keys Ja Kein Finding
Sensitive Data Exposure (PII in Logs) Ja Kein Finding
SSRF via urllib.request / externe URL-Weitergabe Ja Kein Finding
URL-Schema-Validierung an Media-Subprocessen Ja Kein Finding
Kryptographische Schwachstellen Ja Kein Finding
Symlink-Angriffe auf privilegierte Dateioperationen Ja Kein Finding
Mountpoint-Manipulation via Konfig-Datei Ja Kein Finding (Fix in v1.1.15)
WireGuard-Hook-Ausführung via Import Ja K1 → FP (kein Boundary Crossing)
PATH-Hijacking via shutil.which (R3-K1) Ja Geschlossen (R3)
Agent-CLI Pfad-Confinement (R3-K3) Ja Geschlossen (R3)

Auditor: Claude Sonnet 4.6 (Anthropic) — Automatisiertes Multi-Agenten-Sicherheits-Review + unabhängige False-Positive-Filterrunde
Projektverantwortlicher: Sven Fröhlich
Datum: 29. Juni 2026
Analysierter Codestand: e334324a … 920cfc9b + Arbeitsstand (modified/untracked), gesamt 40+ Dateien — Runde 4
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