3 Findings bestätigt · K1 HIGH, K2/K3 MEDIUM · alle nachgezogen und geschlossen
Datum
28. Juni 2026
Analysierte Version
v1.1.14 · Runde 3
Bestätigte Findings
3
Bewertete Kandidaten
7
Konfidenz-Schwelle
≥ 8 / 10
Severity
1 HIGH + 2 MEDIUM (geschlossen)

Zusammenfassung

Die dritte statische Sicherheitsanalyse des NetMon-Arbeitsstands v1.1.14 durch ein Multi-Agenten-System (Claude Sonnet 4.6) mit anschließender manueller Verifikation bestätigte in Runde 3 insgesamt 3 Findings: PATH-Hijacking in rkhunter_manager.py (HIGH), Pfad-Konfinement im lokalen Agent-Runner (MEDIUM) und fehlende Launcher-Pfadbegrenzung im Fun-Controller (MEDIUM). Alle drei Punkte sind im aktuellen Codestand inzwischen geschlossen.

K1 (geschlossen): rkhunter_manager.py begrenzt WEB_CMD jetzt auf Trusted Prefixes unter /usr/bin/, /bin/ und /usr/local/bin/. User-kontrollierte PATH-Treffer wie ~/.local/bin/wget werden verworfen.

K2 (geschlossen): fun_controller.py startet jetzt nur noch validierte Python-Launcher innerhalb von fun_games_dir. Der Pfad wird via realpath() und Managed-Path-Check begrenzt.

K3 (geschlossen): agent/runner.py prueft jetzt die Pfadargumente fuer black, ruff, pytest und ls zusaetzlich gegen REPO_ROOT. Absolute oder relative Ziele ausserhalb des Repositories werden abgelehnt.

Methodik

Analysierte Module (Runde 3)

Datei / ModulFokusErgebnis
netmon/core/rkhunter_manager.pyrkhunter-Konfigurationsreparatur, shutil.which, sudo installFinding K1 geschlossen
netmon/features/fun_controller.pySpieleordner-Scan, subprocess.Popen python3Finding K2 geschlossen
agent/runner.pyAgent-CLI-Allowlist, black/ruff/pytest/ls PfadrestriktionFinding K3 geschlossen
netmon/core/tooling.pyimportlib-Modul-Loading aus sys.pathAusgeschlossen K4
netmon/services/lang_service.pylang_code-Pfad-Traversal, json.loadAusgeschlossen K5
netmon/ui/tabs/cleanup_assistant_tab.pyTOCTOU-Race vor shutil.rmtreeAusgeschlossen K6
netmon/features/links_controller.py.desktop-Exec-Parsing, xdg-openAusgeschlossen K7
netmon/core/coordinator.py + state.pyZustandsverwaltung, makedirsKein Finding
netmon/core/support_bundle.py + diagnostics.pyDateioperationen, SubprocessKein Finding
netmon/features/process_guard_controller.pyUI-ZustandsmanagementKein Finding
netmon/features/repository_guard_controller.pySnippet-Generierung, shlex.quoteKein Finding
netmon/features/roots_baseline_guard_controller.pysudo cat/sha256sum mit Pfad-AllowlistKein Finding
netmon/services/process_guard_service.pyRead-Only-AnalyseKein Finding
netmon/services/repository_guard_service.pyAPT-Source-Parsing, flatpak-SubprocessKein Finding
netmon/services/network_helpers.pyis_safe_trace_target, normalize_external_urlKein Finding
netmon/services/startup_guard_service.py.desktop/.service SHA256-LesenKein Finding
netmon/netmon_security_parser.py + _store.pyIn-Memory-AnalyseKein Finding

Bestätigte Findings

K1 — PATH-Hijacking in rkhunter_manager
netmon/core/rkhunter_manager.py · Zeilen 11–23, 141
HIGH Konfidenz 9/10 · geschlossen

Bestätigtes Finding: _preferred_web_cmd() konnte user-kontrollierte PATH-Treffer wie ~/.local/bin/wget ungefiltert nach WEB_CMD=... in die rkhunter-Konfiguration uebernehmen. Ein nachfolgendes rkhunter --update haette diese Binary mit Root-Rechten ausgefuehrt.

Fix: Der aktuelle Codestand begrenzt die Rueckgabe jetzt auf Trusted Prefixes unter /usr/bin/, /bin/ und /usr/local/bin/. Untrusted Treffer werden verworfen; falls nur solche Kandidaten vorhanden sind, bleibt WEB_CMD leer.

# rkhunter_manager.py — aktueller Stand TRUSTED_WEB_CMD_PREFIXES = ("/usr/bin/", "/bin/", "/usr/local/bin/") def _preferred_web_cmd(): for candidate in ("wget", "curl"): resolved = shutil.which(candidate) if resolved and any( str(resolved).startswith(prefix) for prefix in TRUSTED_WEB_CMD_PREFIXES ): return resolved return ""
GESCHLOSSEN — Trusted-Prefix-Allowlist verhindert PATH-Hijacking und moegliche Privilege Escalation ueber user-kontrollierte Binaries.
K2 — Fun-Launcher startet Python-Dateien ohne Pfad-Confinement
netmon/features/fun_controller.py · Zeilen 55–79, 82–111, 266–291
MEDIUM Konfidenz 8/10 · geschlossen

Bestätigtes Finding: Der Fun-Launcher konnte Python-Dateien ueber subprocess.Popen(["python3", game["path"]]) starten, ohne den Launcher-Pfad selbst gegen den verwalteten Spieleordner zu begrenzen.

Fix: Der aktuelle Codestand akzeptiert nur noch `.py`-Dateien innerhalb von fun_games_dir. Der Pfad wird via realpath() gegen den Spieleordner geprueft und bei verfuegbarem App-Kontext zusaetzlich mit _is_safe_netmon_managed_path() abgesichert.

GESCHLOSSEN — ausserhalb des verwalteten Spielebereichs liegende Launcher werden nicht mehr gestartet.
K3 — Agent-CLI: black/ruff ohne Pfad-Allowlist schreiben beliebige Dateien
agent/runner.py · Zeilen 18–60
MEDIUM Konfidenz 9/10 · geschlossen

Bestätigtes Finding: Der lokale Agent-Runner liess absolute oder relative Pfadargumente an black, ruff, pytest und ls durch, solange nur der Basisbefehl auf der Allowlist stand.

LLM-Prompt-Injection / CLI-Argument mit absolutem Pfad → run_command("black /home/user/.bashrc") → parts[0] = "black" → Allowlist-Check BESTANDEN [Zeile 31] → parts[1] = "/home/user/.bashrc" → KEIN Pfad-Check → subprocess.run(["black", "/home/user/.bashrc"], cwd=REPO_ROOT) → black schreibt /home/user/.bashrc außerhalb REPO_ROOT um ← Live-Test bestätigt

run_command() pruefte urspruenglich nur parts[0] gegen die Allowlist. black, ruff, pytest und ls konnten dadurch absolute oder relative Pfade ausserhalb von REPO_ROOT erreichen.

GESCHLOSSEN — Pfadargumente werden jetzt auf REPO_ROOT begrenzt. Das gilt fuer black, ruff, pytest und ls, inklusive pytest-Node-IDs wie tests/test_x.py::test_name.

Ausgeschlossene Kandidaten

K4 — importlib-Modul-Loading aus sys.path (tooling.py)
netmon/core/tooling.py · Zeilen 47–81
Ausgeschlossen Konfidenz 7/10 → FP

load_speedtest_module_from_file() sucht netmon/modules/speedtest.py via sys.path (enthält "" = CWD). Bei PYTHONPATH-Injektion oder Ausführung aus einem beschreibbaren Verzeichnis könnte eine böswillige Datei geladen werden.

AUSGESCHLOSSEN — Angriff erfordert Kontrolle über Umgebungsvariablen (PYTHONPATH) oder CWD vor dem Prozessstart. Ein Angreifer mit dieser Fähigkeit hätte bereits vollständige Codeausführung als derselbe Benutzer ohne diesen Umweg.
K5 — lang_code-Pfad-Traversal in LangService (lang_service.py)
netmon/services/lang_service.py · Zeile 12
Ausgeschlossen Konfidenz 7/10 → FP

os.path.join(base_path, f"{lang_code}.json") — ein Angreifer der settings["language"] auf ../../etc/passwd setzen kann, könnte beliebige JSON-parsierbare Dateien lesen.

AUSGESCHLOSSEN — Nur lesend (json.load), auf JSON-parsierbare Dateien beschränkt. Erfordert Schreibzugriff auf die Settings-Datei im Benutzerverzeichnis (gleiche Privilege-Ebene). Die Settings-Datei ist bereits vom Benutzer lesbar und schreibbar.
K6 — TOCTOU-Race vor shutil.rmtree (cleanup_assistant_tab.py)
netmon/ui/tabs/cleanup_assistant_tab.py · Zeilen 2307–2464
Ausgeschlossen Konfidenz 7/10 → FP

lstat()-Check (Symlink-sicher) und nachfolgendes shutil.rmtree() sind nicht atomar — ein Symlink könnte dazwischen gesetzt werden.

AUSGESCHLOSSEN — Python 3.12+ schützt shutil.rmtree gegen Symlinks per NotADirectoryError. Race-Window extrem eng; erfordert präzise Timing-Koordination durch denselben Benutzer. Als Defense-in-Depth-Empfehlung notiert (siehe Abschnitt 6).
K7 — .desktop-Exec-Parsing via links_controller.py
netmon/features/links_controller.py · Zeilen 804–813, 882–894
Ausgeschlossen Konfidenz 7/10 → FP

parse_desktop_entry() liest Exec=-Zeilen aus ~/.local/share/applications/*.desktop; Exec-Pfad wird via subprocess.Popen ausgeführt.

AUSGESCHLOSSEN — ~/.local/share/applications/ ist das Standard-XDG-Verzeichnis für benutzerinstallierte Anwendungen; das Ausführen von Binaries aus Exec=-Zeilen ist das erwartete Verhalten von Desktop-Umgebungen. Kein Privilege-Boundary-Crossing — gleicher Benutzer.

Sicherheitsverbesserungen seit Runde 2

URL-Schema-Validierung Radio-Modul (bereits implementiert, Runde 2 bestätigt) ALLOWED_RADIO_STREAM_SCHEMES = {"http", "https", "rtsp", "rtmp"} in _normalize_station_stream_url() — verhindert SSRF via mpv/urllib.request.
ClamAV Tempdir Symlink-Schutz (seit Runde 1) _safe_makedirs_no_symlink() prüft via os.lstat() vor Verzeichnisanlage auf Symlinks — wirft RuntimeError.
82 Proxy-Methoden aus app.py entfernt (Runde 2) Angriffsfläche reduziert; alle via refactor_safety.py auf Null-Aufrufer verifiziert.
HDD-Mountpoint-Validierung (Runde 2) _slot_mountpoint() mit os.path.realpath() + _SAFE_MOUNT_BASES-Allowlist — verhindert Privilege-Escalation via präpariertes Filesystem.
rkhunter WEB_CMD: Trusted-Prefix-Allowlist aktiv TRUSTED_WEB_CMD_PREFIXES = ("/usr/bin/", "/bin/", "/usr/local/bin/") in _preferred_web_cmd() (Zeile 16–26) — verhindert PATH-Hijacking via ~/.local/bin.
Agent-Runner: Repo-Pfad-Confinement black, ruff, pytest und ls pruefen Pfadargumente jetzt gegen REPO_ROOT.
Fun-Launcher: Launcher-Pfade auf Spieleordner begrenzt Nur noch validierte Python-Launcher innerhalb von fun_games_dir werden gestartet.
WireGuard Interface-Name-Validierung (neu, Runde 3) wg_profile_path() validiert Interface-Namen via re.fullmatch(r'[A-Za-z0-9_.-]+', ...) und os.path.commonpath()-Confinement auf /etc/wireguard.
roots_baseline_guard: sudo-Calls mit Pfad-Allowlist abgesichert _is_allowed_guard_path(path) mit os.path.realpath()-Normalisierung gegen ROOTS_GUARD_DEFAULT_AREA_PATHS — verhindert sudo-cat auf beliebige Pfade.

Hardening-Empfehlungen

Die bestätigten Findings aus Runde 3 sind geschlossen. Offen bleiben nur zusätzliche Defense-in-Depth-Maßnahmen ohne unmittelbaren Exploitpfad: