OpenReplay: Unauthentifizierter Stored XSS über Tracker-Eventdaten führt zur Dashboard-Übernahme
Ein anonymer Angreifer platziert über das Tracking-SDK Eventdaten, die beim Öffnen im Dashboard JavaScript ausführen und über den JWT im localStorage zur Account-Übernahme führen.
Advisory-ID: TP-2026-023
Produkt: OpenReplay (Session-Replay- und Produktanalyse-Plattform)
Schwachstellentyp: Stored Cross-Site-Scripting (CWE-79)
CVE: CVE-2026-55879
CVSS 3.1: 9.3 (Kritisch) · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N
Betroffene Versionen: >= 1.24.0
Behoben in: 1.25.0
Hersteller-Advisory: GHSA-3mfc-7hf4-jfxh
Gemeldet: 29. Mai 2026
Zusammenfassung
OpenReplay ist eine Session-Replay- und Produktanalyse-Plattform. Das Tracking-SDK nimmt Events allein über den öffentlichen Projektschlüssel entgegen, also ohne Authentifizierung des absendenden Nutzers. Benutzerdefinierte Eventnamen und Seiten-URLs werden ohne Ausgabe-Kodierung gespeichert und später im Dashboard gerendert, wo die TextEllipsis-Komponente den Wert per innerHTML zuweist und damit Markup-Injektion erlaubt. Öffnet ein angemeldeter Nutzer das Event in der Datenverwaltung, führt das eingebettete Skript im Dashboard-Origin aus. Da der Session-JWT im localStorage liegt und keine Content-Security-Policy ausgeliefert wird, liest das Skript den Token aus und übernimmt den Account. turingpoint hat den Ablauf verifiziert und verantwortungsvoll gemeldet; der Hersteller hat ihn in 1.25.0 behoben.
Ursache
Das Analyse-Backend speichert vom Tracker gelieferte Eventfelder unverändert: den Eventnamen (backend/pkg/db/clickhouse/connector.go:850), die Properties (:835) und die Seiten-URL (:460), und die Go-API gibt sie roh zurück (backend/pkg/analytics/events/events.go:201 GetEventByID). Im Dashboard rendert das Event-Detail-Modal die Werte in der Standard-Ansicht über <TextEllipsis> (frontend/app/components/DataManagement/Activity/EventDetailsModal.tsx:234). Deren Breitenmessung setzt tag.innerHTML = text und hängt das Element an document.body an (frontend/app/components/ui/TextEllipsis/TextEllipsis.js:20), wobei sie mit element.innerText aufgerufen wird, sodass der von React escapte Text zurück in lebendes HTML geparst wird und der onerror-Handler feuert. Eine zweite Senke, <pre dangerouslySetInnerHTML> in der JSON-Ansicht (EventDetailsModal.tsx:253), rendert dieselben Rohdaten ohne Sanitizer. OpenReplay liefert keine Content-Security-Policy aus, sodass das Inline-Skript im Dashboard-Origin ausgeführt wird und den JWT aus localStorage.UserStore.jwt lesen kann.
Proof of Concept
Über das Tracking-SDK mit dem öffentlichen Projektschlüssel (anonym):
tracker.event("<img src=x onerror=window.__XSS_FIRED=document.domain>", {})
Opfer (angemeldet) öffnet:
GET /<projectId>/data-management/activity?event_id=<id>
-> onerror feuert im Dashboard-Origin, liest localStorage.UserStore.jwt
Die fehlende Ausgabe-Kodierung speichert den Eventnamen unverändert, und beim Öffnen parst TextEllipsis den über innerText zurückgewonnenen Text per innerHTML zu einem lebenden Element, dessen onerror-Handler ohne CSP ausgeführt wird.
Auswirkung
- Anonyme Angreifer führen Skripte in der Sitzung jedes angemeldeten Dashboard-Nutzers aus, der das präparierte Event öffnet.
- Vollständige Account-Übernahme durch Diebstahl des JWT aus dem
localStorage. - Zugriff auf Sitzungsaufzeichnungen, Dashboards, Projekteinstellungen und Mitgliederverwaltung des Opfers.
- Erfordert nur Kenntnis des öffentlichen Projektschlüssels; das Payload wird über einen
?event_id=-Deeplink ohne weitere Interaktion ausgelöst.
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.
