OpenReplay: Cross-User-IDOR in Notizen und Dashboard-Widgets
Ein angemeldeter Nutzer löscht oder verändert private Notizen und Dashboard-Widgets anderer Nutzer, weil drei Schreiboperationen die Eigentümerprüfung ihrer Lese-Pendants auslassen.
Advisory-ID: TP-2026-024
Produkt: OpenReplay (Session-Replay- und Produktanalyse-Plattform)
Schwachstellentyp: Autorisierungsumgehung über einen nutzerkontrollierten Schlüssel (CWE-639)
CVE: CVE-2026-55880
CVSS 3.1: 7.1 (Hoch) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Betroffene Versionen: <= 1.27.0
Behoben in: 1.25.0
Hersteller-Advisory: GHSA-9xfv-p2fx-vmx9
Gemeldet: 29. Mai 2026
Zusammenfassung
OpenReplay ist eine Session-Replay- und Produktanalyse-Plattform, in der Notizen und Dashboards je Nutzer privat sein können. Drei Schreiboperationen lassen die Eigentümerprüfung aus, die ihre Lese- und Bearbeitungs-Pendants durchführen. Die Funktion notes.delete filtert nur nach Notiz- und Projekt-ID und lässt den Nutzer-ID-Check weg, den notes.edit und notes.get_note durchführen. Ebenso umgehen dashboards.update_widget und dashboards.remove_widget das Eigentümer-Prädikat, das dashboards.add_widget und die Dashboard-Lesepfade anwenden. Da die Objekte fortlaufende Integer-IDs tragen, kann jeder angemeldete Nutzer fremde private Notizen und Widgets über ID-Aufzählung löschen oder verändern, ohne sie lesen zu dürfen. turingpoint hat den Ablauf verifiziert und verantwortungsvoll gemeldet; der Hersteller hat ihn in 1.25.0 behoben.
Ursache
Im Lesepfad ist die Eigentümerprüfung vorhanden: notes.edit filtert mit AND user_id (notes.py:162) und die Dashboard-Pfade mit dem Prädikat (user_id OR is_public) (dashboards.py:128). notes.delete setzt jedoch nur UPDATE sessions_notes SET deleted_at WHERE note_id AND project_id ohne jeden Nutzer- oder is_public-Bezug (notes.py:175), und der Handler verwirft die Nutzer-ID vollständig (core_dynamic.py:524 delete_note). Genauso schreiben dashboards.update_widget (dashboards.py:173) und dashboards.remove_widget (:186) auf dashboard_widgets allein über dashboard_id und widget_id, anders als das geprüfte add_widget (:160). Alle betroffenen Routen laufen unter OR_context, verlangen also nur einen beliebigen authentifizierten Kontext und keine erhöhte Rolle. Da die IDs fortlaufend vergeben werden, ist das Zielobjekt eines anderen Nutzers ohne Trefferaufwand aufzählbar.
Proof of Concept
Als angemeldeter Nutzer mit niedriger Rolle (eine fremde private Notiz mit fortlaufender note_id):
PUT /<projectId>/notes/<fremde_note_id>/delete
Authorization: Bearer <Nutzer-JWT>
-> 200 {state: success}, deleted_at wird gesetzt (obwohl die Notiz nicht lesbar ist)
Die Schreiboperation prüft weder user_id noch is_public, sodass die Bedingung allein über die geratene note_id greift; derselbe fehlende Check gilt für update_widget und remove_widget auf fremden privaten Dashboards.
Auswirkung
- Angemeldete Nutzer löschen die privaten Sitzungsnotizen anderer Nutzer.
- Angemeldete Nutzer entfernen oder verändern Widgets auf den privaten Dashboards anderer Nutzer.
- Kein Datenabfluss; betroffen sind Integrität und Verfügbarkeit fremder privater Objekte.
- Fortlaufende IDs ermöglichen die Ziel-Aufzählung ohne Audit-Spur.
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.
