## Ergebnis: **NICHT FREIGEGEBEN** ### Critical - **Unauthentifizierte Gesundheitsdaten auf allen Interfaces / DNS-Rebinding-Risiko** `deploy/systemd/health-dashboard.service:11` bindet an `0.0.0.0`. Gleichzeitig liefern `health_dashboard_server.py:202-251` Dashboard, Dokumente und Berichte ohne Authentisierung und ohne Host-Allowlist aus. Die Origin-Prüfung gilt nur für POST; ein beliebiger `Host` wird akzeptiert. Damit können sensible Daten über unerwartete LAN-Interfaces oder per DNS-Rebinding erreichbar werden. **Fix:** Nur an eine explizite Tailnet-IP bzw. `127.0.0.1` hinter authentisiertem Reverse Proxy binden; zusätzlich `HEALTH_DASHBOARD_ALLOWED_HOSTS` einführen und **jede** Anfrage vor Routing gegen kanonisch geparste erlaubte Hosts prüfen. Keine Ableitung der Vertrauenswürdigkeit aus dem vom Client gelieferten `Host`. ### Important - **Fehlerhafte Pfadgrenzen ermöglichen Dateien außerhalb der vorgesehenen Verzeichnisse** `health_dashboard_server.py:55-57` und `82-87` verwenden String-`startswith()` für Pfad-Containment. Beispielsweise besteht `/.../Gesundheit-evil/...` den Präfixtest gegen `/.../Gesundheit`; Symlinks können den Report-Pfad ebenfalls verlassen. **Fix:** `resolved.is_relative_to(BASE.resolve())` bzw. `REPORTS.resolve()` verwenden, nur reguläre Dateien zulassen und Symlink-Policy explizit festlegen. Idealerweise Dokumentpfade nur aus streng erlaubten Unterverzeichnissen bedienen. - **Systemd-Sandbox verhindert den neuen Schreibendpunkt** `deploy/systemd/health-dashboard.service:18-20` setzt `ProtectHome=read-only`, `ProtectSystem=strict` und das komplette Gesundheitsverzeichnis auf `ReadOnlyPaths`. Der POST-Pfad schreibt jedoch über `health_dashboard_server.py:127-138` in die SQLite-DB und regeneriert den Bericht. Im realen Service endet ein gültiger Check-in daher voraussichtlich mit HTTP 500. **Fix:** Minimale `ReadWritePaths` ausschließlich für die benötigte DB und das Report-Ausgabeverzeichnis definieren; Generatorausgabe atomar über temporäre Datei plus `os.replace()` schreiben. Danach den tatsächlichen Unit-Kontext synthetisch testen. - **Keine Serialisierung des Schreib-/Regenerationspfads** Der `ThreadingHTTPServer` (`health_dashboard_server.py:314`) kann mehrere POSTs gleichzeitig ausführen; `write_symptom_checkin()` (`127-138`) startet parallel Quick-Add und Dashboard-Generator gegen dieselbe DB und dieselbe HTML-Datei. Das kann SQLite-Locks, verlorene/duplizierte Check-ins oder eine teilweise geschriebene Dashboard-Datei verursachen. **Fix:** Prozessweiten Write-Lock um Quick-Add plus Regeneration, idempotente Tageslog-Semantik und atomare HTML-Ersetzung einführen; Parallel-POST-Test ergänzen. ### Weitere Feststellung - **CSP blockiert vorhandenen Inline-Eventhandler** `health_dashboard_v4.py:812` verwendet `oninput='filterDashboard(...)'`. Ein Nonce auf `