From 72af3c0e1c133076a4507598c6bad2188a54c5c6 Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Thu, 16 Jul 2026 18:11:10 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20#129:=20Stored=20XSS=20=C3=BCber=20suppli?= =?UTF-8?q?er=5Fname=20im=20KI-Kontierungsvorschlag=20verhindert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changes.md | 5 +++++ src/Views/belege/detail.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Changes.md b/Changes.md index c8f381c..a838a7d 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,11 @@ --- +## 2026-07-16 – Fix: Stored XSS über KI-Kontierungsvorschlag (supplier_name) in Beleg-Detailansicht (Issue #129) + +- **Mittel-Hoch:** `supplier_name` aus dem per LLM erzeugten Kontierungsvorschlag (`KontierungsvorschlagService`) wird nur `trim()`t und ungeprüft in `belege.ki_vorschlag` (JSON) gespeichert. `_showKiBadgeDone()` in `src/Views/belege/detail.php` baute daraus String-Konkatenation und wies sie ohne Escaping über `innerHTML` zu. Da der Belegtext (PDF/Bild/ZUGFeRD-XML) von einem externen Rechnungssteller stammt, konnte ein präparierter Beleg das LLM per Prompt-Injection dazu bringen, für `supplier_name` HTML/JS-Payload statt eines Firmennamens auszugeben – dieser wurde beim Öffnen des Belegs im Browser-Kontext des eingeloggten Nutzers ausgeführt (CWE-79). +- **`src/Views/belege/detail.php`:** `_showKiBadgeDone()` verwendet nun die bereits vorhandene `_esc()`-Hilfsfunktion, um `v.supplier_name` vor der Einbettung in `innerHTML` HTML-zu-escapen. Andere Ausgabepfade von `supplier_name`/`buchungstext` (`.value`, `.textContent`, `.dataset`) waren bereits sicher. + ## 2026-07-12 – Fix: SSRF über ungeprüftes nextcloud_url-Feld beim Belegimport (Issue #127) - **Mittel:** Anders als bei `fints_url` (Issue #118) wurde die in den Einstellungen gespeicherte `nextcloud_url` weder beim Speichern noch bei der Verwendung geprüft. `NextcloudImportService` baute daraus ungefiltert die WebDAV-Basis-URL für PROPFIND-, GET- und MOVE/DELETE-Requests samt Basic-Auth-Credentials; ein authentifizierter Benutzer mit Zugriff auf die Einstellungen konnte so interne Ziele (`127.0.0.1`, internes Netz, Cloud-Metadata-Endpunkt `169.254.169.254`) über den Belegimport-Cron ansprechen (CWE-918). Zusätzlich folgte der verwendete cURL-Handle HTTP-Redirects, wodurch eine nachträgliche Host-Prüfung per Weiterleitung hätte umgangen werden können. diff --git a/src/Views/belege/detail.php b/src/Views/belege/detail.php index ef5bb6e..b2c46a0 100644 --- a/src/Views/belege/detail.php +++ b/src/Views/belege/detail.php @@ -1050,7 +1050,7 @@ function _showKiBadgeDone(arr) { const katTxt = katOpt ? katOpt.text : v.kategorie_konto_id; const zhlTxt = zhlOpt ? zhlOpt.text : v.zahlungskonto_id; const supTxt = v.supplier_name - ? ' · Lieferant: ' + v.supplier_name + (v.supplier_found === false ? ' (neu – bitte prüfen)' : '') + ? ' · Lieferant: ' + _esc(v.supplier_name) + (v.supplier_found === false ? ' (neu – bitte prüfen)' : '') : ''; // Erste Zeile (bereits ins Formular übertragen)