Teable: Stored XSS in Benachrichtigungen über den Anzeigenamen
Ein selbst registriertes Konto führt über seinen Anzeigenamen Skriptcode in der Sitzung jedes Nutzers aus, den es in eine Basis einlädt.
Advisory-ID: TP-2026-111
Produkt: Teable (No-Code-Datenbank und Tabellenanwendung)
Schwachstellentyp: Stored Cross-Site Scripting (CWE-79)
CVE: pending
CVSS 3.1: 4.6 (Mittel) · CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N
Betroffene Versionen: < release.2026-10-12T12-45-53Z.3331 (getestet mit 1.10.0)
Hersteller-Advisory: GHSA-3rmq-5wwc-x8w2
Behoben in: release.2026-10-12T12-45-53Z.3331
Gemeldet: 16. Juli 2026
Zusammenfassung
Teable ist eine No-Code-Datenbank mit Tabellenoberfläche, in der Nutzer sich gegenseitig in Basen einladen und in Datensätzen zuweisen. Die In-App-Benachrichtigungen setzten ihren Text per dangerouslySetInnerHTML als HTML in die Seite, und der Text enthielt den Anzeigenamen des auslösenden Nutzers ohne jedes Escaping. Ein selbst registrierter Nutzer setzt seinen Anzeigenamen auf HTML mit Event-Handler, lädt das Opfer in eine eigene Basis ein und weist es in einem Benutzerfeld zu. Öffnet das Opfer das Benachrichtigungsfeld, läuft das Skript des Angreifers im angemeldeten Kontext des Opfers und kann in dessen Namen API-Token anlegen, die E-Mail-Adresse ändern oder Daten abziehen.
Ursache
Die Benachrichtigungskomponente rendert die Nachricht mit <div dangerouslySetInnerHTML={{ __html: message }}> in beiden Zweigen (apps/nextjs-app/src/features/app/components/notifications/notification-component/LinkNotification.tsx:46,60), ebenso das Popup für wichtige Hinweise (apps/nextjs-app/src/features/app/components/notifications/ImportantNotificationPopup.tsx:58). Die Nachricht entsteht in getShowMessage (apps/nextjs-app/src/features/app/components/notifications/notification-component/get-show-message.ts:6) aus der Vorlage collaboratorCellTag.subject, die {{fromUserName}}, {{fieldName}} und {{tableName}} ohne HTML-Escaping einsetzt (packages/common-i18n/src/locales/en/common.json:1212). Der Anzeigename wird über PATCH /api/user/name als z.string().min(1).max(100) ohne jede Filterung gespeichert (packages/openapi/src/user/update-name.ts:11). CollaboratorNotificationListener übernimmt Absendername, Feld- und Tabellennamen unverändert in die Benachrichtigung des Opfers (collaborator-notification.listener.ts:98-110). Die Selbstregistrierung ist standardmäßig offen und die Frontend-CSP enthält keine script-src-Direktive, sodass der Inline-Handler ausgeführt wird.
Proof of Concept
PATCH /api/user/name
Cookie: <Session eines selbst registrierten Kontos>
{"name": "<img src=x onerror=alert(document.domain)>"}
Angreifer: Space, Basis und Tabelle anlegen, Opfer einladen,
Benutzerfeld anlegen, Opfer in einer Zelle zuweisen
Opfer: App öffnen -> Glocke anklicken -> alert(document.domain)
Die Zuweisung erzeugt für das Opfer eine Benachrichtigung, deren Text den Anzeigenamen roh enthält. Beim Öffnen des Benachrichtigungsfelds setzt React den Text als HTML ein, und der onerror-Handler läuft im Ursprung der Teable-Instanz.
Auswirkung
- Ausführung von Angreifer-JavaScript in der angemeldeten Sitzung jedes Nutzers, den der Angreifer per Einladung erreicht.
- Anlegen von API-Token und Ändern der E-Mail-Adresse im Namen des Opfers bis zur Kontoübernahme.
- Lesen und Ausleiten aller Basen und Tabellen, auf die das Opfer Zugriff hat.
- Wiederholte Ausführung bei jedem Öffnen der Benachrichtigungen, solange die Benachrichtigung besteht.
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.
