Zurück zum Blog
13. Mai 2026

Supabase RLS-Fehlkonfiguration: Wie eine fehlende Richtlinie jedes Nutzerprofil offenlegte

Viktor Bulanek
Founder & CTO, Penetrify
MSc IT Security · 20+ years in security · 4x Ex-CTO

Die Anwendung sah produktionsreif aus. Eine saubere Benutzeroberfläche, eine funktionierende Stripe-Integration, ein ausgefeilter Onboarding-Prozess. Sie war auf Product Hunt vorgestellt worden, hatte in der ersten Woche über 200 Nutzer gewonnen und generierte bereits MRR. Der Gründer hatte sie in 48 Stunden während eines Hackathon-Wochenendes mit Next.js und Supabase entwickelt, der bevorzugten Technologie für alle, die schnell liefern wollen.

Acht Minuten nach Beginn des Penetrify-Scans haben wir eine Kritische Schwachstelle gemeldet: Der Profil-Datensatz jedes Nutzers – Name, E-Mail, Kontometadaten – war für jeden anderen authentifizierten Nutzer über die automatisch generierte REST API von Supabase lesbar. Keine ausgeklügelte Angreifertechnik erforderlich. Tauschen Sie einfach Ihre Nutzer-ID in der URL gegen eine andere aus.

Dies ist die Geschichte, wie es dazu kam, warum es häufiger vorkommt, als man zugeben möchte, und wie die Lösung genau aussah.


Was Supabase Row Level Security ist – Und was passiert, wenn es deaktiviert ist

Supabase basiert auf PostgreSQL und stellt Ihre Datenbanktabellen direkt über eine REST API (via PostgREST) und eine JavaScript-Client-Bibliothek bereit. Dies ist wirklich leistungsstark für die schnelle Entwicklung: Sie können Ihre Datenbank vom Frontend aus abfragen, ohne eine einzige API-Route schreiben zu müssen.

Der Mechanismus, der Nutzer daran hindert, die Daten anderer zu lesen, wird Row Level Security (RLS) genannt. RLS ist eine PostgreSQL-Funktion, mit der Sie Richtlinien definieren können, die steuern, welche Zeilen ein bestimmter Datenbanknutzer SELECT, INSERT, UPDATE oder DELETE darf. In einer Supabase-Anwendung würden Sie typischerweise eine Richtlinie wie diese schreiben:

-- Nur Nutzern erlauben, ihr eigenes Profil zu lesen
CREATE POLICY "Users can view own profile"
  ON profiles
  FOR SELECT
  USING (auth.uid() = user_id);

Wenn RLS aktiviert ist und eine solche Richtlinie vorhanden ist, gibt eine Abfrage für das Profil eines anderen Nutzers null Zeilen zurück – die Datenbank erzwingt die Zugriffskontrolle auf Zeilenebene, bevor Daten die Anwendung erreichen.

Wenn RLS deaktiviert ist oder keine Richtlinie existiert, verhält sich die Tabelle so, als ob jede Zeile für jede authentifizierte Anfrage öffentlich wäre. Die REST API von Supabase, zugänglich unter https://[project].supabase.co/rest/v1/profiles, gibt alle Zeilen der Tabelle – die Daten jedes Nutzers – an jeden zurück, der ein gültiges JWT von diesem Projekt besitzt.


Was wir gefunden haben: Fünf Schwachstellen, zwei davon kritisch

Der Scan lief acht Minuten lang im Schnellmodus gegen die Live-Anwendung. Hier sind die Schwachstellen in der Reihenfolge ihrer Schwere:

KRITISCH – Supabase RLS nicht auf der Profile-Tabelle aktiviert

Die Profile-Tabelle hatte RLS deaktiviert. Jeder authentifizierte Nutzer konnte sie über den Supabase REST-Endpunkt abfragen und alle Nutzerdatensätze abrufen. Die Anfrage, die dies demonstrierte:

GET /rest/v1/profiles?select=*
Authorization: Bearer [any valid user JWT]

HTTP/1.1 200 OK
[
  {"id": "uuid-1", "email": "user1@example.com", "full_name": "...", ...},
  {"id": "uuid-2", "email": "user2@example.com", "full_name": "...", ...},
  ... (alle über 200 Nutzerdatensätze)
]

Gemäß DSGVO handelt es sich hierbei um eine Offenlegung personenbezogener Daten, die jeden registrierten Nutzer betrifft. Der Supabase Anon-Key ist standardmäßig im Frontend-JavaScript-Bundle eingebettet – es ist sicher, ihn öffentlich zugänglich zu machen, wenn RLS korrekt konfiguriert ist, da der Key allein keinen erhöhten Zugriff gewährt. Ohne RLS wird er zu einem Generalschlüssel für alle Nutzerdaten.

KRITISCH – E-Mail-Verifizierung nicht auf geschützten Endpunkten erzwungen

Supabase erlaubt standardmäßig Anmeldungen mit E-Mail und Passwort und sendet eine Bestätigungs-E-Mail zur Verifizierung der Adresse. Die Backend-API-Routen der Anwendung prüften jedoch nicht, ob der anfragende Nutzer seine E-Mail bestätigt hatte, bevor der Zugriff auf geschützte Funktionen gewährt wurde.

Ein Angreifer konnte sich mit victim@example.com (der E-Mail-Adresse eines echten Benutzers) registrieren, die E-Mail-Verifizierung vollständig umgehen und sofort auf die geschützten API-Routen der Anwendung zugreifen, als ob er der Besitzer dieser E-Mail wäre. In Kombination mit dem RLS-Problem bedeutete dies, dass ein nicht authentifizierter Angreifer die gesamte Benutzerdatenbank exfiltrieren konnte, indem er ein Wegwerfkonto mit einer beliebigen E-Mail-Adresse erstellte.

MEDIUM — IDOR auf /api/export

Die Anwendung verfügte über einen Export-Endpunkt, der eine Benutzer-ID als Abfrageparameter akzeptierte:

GET /api/export?userId=abc123

Serverseitig wurde keine Besitzprüfung durchgeführt. Jeder authentifizierte Benutzer konnte die Daten jedes anderen Benutzers exportieren, indem er seine eigene ID durch die eines Ziels ersetzte. Benutzer-IDs wurden in API-Antworten in der gesamten Anwendung offengelegt, was die Enumeration trivial machte.

MEDIUM — Keine Ratenbegrenzung auf dem Login-Endpunkt

Der Login-Endpunkt akzeptierte Authentifizierungsanfragen mit etwa 500 Anfragen pro Sekunde ohne Drosselung oder Sperrung. Ein Credential-Stuffing-Angriff auf die Benutzerbasis der Anwendung würde auf keinen Widerstand stoßen.

MEDIUM — JWT-Tokens in localStorage ohne Rotation gespeichert

Supabase JWTs wurden in localStorage gespeichert und waren für jedes auf der Seite laufende JavaScript zugänglich. Bei Berechtigungsänderungen erfolgte keine Token-Rotation. Ein erfolgreicher XSS-Angriff auf einer beliebigen Seite würde einem Angreifer eine persistente, gültige Sitzung verschaffen.


Warum das passiert: Die Supabase-Standardfallen

Dies ist keine Geschichte über einen nachlässigen Entwickler. Es ist eine Geschichte über Standardeinstellungen.

Wenn Sie eine neue Tabelle in Supabase erstellen, ist RLS standardmäßig deaktiviert. Die eigene Dokumentation von Supabase beschreibt dies klar und empfiehlt die Aktivierung, aber die Quickstart-Beispiele – jene, denen Entwickler tatsächlich folgen, wenn sie um 2 Uhr morgens während eines Hackathons entwickeln – lassen RLS oft der Kürze halber aus. Man sieht eine funktionierende Abfrage im Beispiel, kopiert das Muster, liefert es aus.

Das Supabase-Dashboard zeigt ein gelbes Warnsymbol bei Tabellen ohne RLS an. Es ist leicht zu übersehen, wenn man sich auf die Benutzeroberfläche, die Zahlungsintegration, den Onboarding-Prozess konzentriert. Es gibt keinen Fehler, keinen Laufzeitfehler, kein offensichtliches Symptom. Alles funktioniert perfekt. Benutzer können sich registrieren, anmelden und die Anwendung nutzen. Die Schwachstelle ist völlig still.

Die gefährlichsten Sicherheitsfehler sind jene, die genau wie korrektes Verhalten aussehen.

Dieses Muster tritt in fast jeder von uns gescannten Supabase-gestützten Anwendung auf, die auf Geschwindigkeit ausgelegt war. Nicht, weil den Entwicklern die Sicherheit egal ist, sondern weil der Zeitdruck eines Hackathons oder Launch-Sprints keinen Raum lässt, jeden Abschnitt der Dokumentation zu lesen.


Die Lösung: Zwei Stunden, kein Code-Rewrite

Der Gründer behob alle fünf Befunde in weniger als zwei Stunden am selben Abend, an dem der Bericht eintraf. Hier ist genau, was getan wurde:

RLS — 15 Minuten im Supabase-Dashboard

Die Aktivierung von RLS und das Hinzufügen geeigneter Richtlinien erforderte keine Code-Änderungen. Im Supabase-Dashboard, unter Tabellen-Editor → Profile → RLS-Richtlinien:

-- RLS für die Tabelle aktivieren (ein Schalter im Dashboard)
-- Dann Richtlinien hinzufügen:

CREATE POLICY "Users can view own profile"
  ON profiles FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can update own profile"
  ON profiles FOR UPDATE
  USING (auth.uid() = user_id);

-- Für Administratorzugriff (falls erforderlich):
CREATE POLICY "Service role has full access"
  ON profiles
  USING (auth.role() = 'service_role');

Nach der Aktivierung von RLS und dem Hinzufügen dieser Richtlinien gab die Massenabfrage null Zeilen für jeden authentifizierten Benutzer zurück, der eine Anfrage für Daten stellte, die nicht seine eigenen waren.

E-Mail-Verifizierung — eine Middleware-Prüfung

Die Next.js API-Routen lasen das Supabase-Benutzerobjekt bereits bei jeder Anfrage aus dem JWT. Das Hinzufügen einer E-Mail-Verifizierungsprüfung war eine einzeilige Überprüfung in der Auth-Middleware:

const { data: { user } } = await supabase.auth.getUser()
if (!user?.email_confirmed_at) {
  return res.status(403).json({ error: 'Email verification required' })
}

IDOR auf /api/export — Einzeiliger Middleware-Fix

Der Fix bestand darin, den vom Benutzer bereitgestellten userId-Parameter durch die eigene ID des authentifizierten Benutzers zu ersetzen, die aus dem verifizierten JWT extrahiert wurde:

// Before (vulnerable)
const userId = req.query.userId

// After (fixed)
const { data: { user } } = await supabase.auth.getUser()
const userId = user.id  // always the authenticated user — can't be spoofed

Ratelimiting — Vercels integriertes Ratelimiting

Die Anwendung wurde auf Vercel gehostet. Das Hinzufügen von Ratelimiting zum Login-Endpunkt erforderte das Hinzufügen des @upstash/ratelimit-Pakets und das Umschließen der Route – etwa 20 Codezeilen. Der Gründer implementierte diesen Fix am nächsten Morgen.


Die GDPR-Offenlegung

Das RLS-Problem betraf alle über 200 registrierten Benutzer. Ihre vollständigen Profilinformationen – E-Mail-Adressen, Anzeigenamen und alle anderen in der Profiltabelle gespeicherten Felder – waren für jeden anderen authentifizierten Benutzer während der gesamten Betriebszeit der Anwendung lesbar.

Gemäß Artikel 33 der GDPR muss eine Verletzung des Schutzes personenbezogener Daten, die „voraussichtlich zu einem Risiko für die Rechte und Freiheiten natürlicher Personen führt“, der zuständigen Aufsichtsbehörde innerhalb von 72 Stunden nach Bekanntwerden gemeldet werden. Ob diese spezielle Verletzung diese Schwelle überschritt, hing von der Sensibilität der gespeicherten Daten und der Anzahl der tatsächlich aufgerufenen Benutzerdaten ab – aber der Gefährdungszeitraum war offen.

Der Gründer rotierte alle sensiblen Konfigurationswerte, aktivierte RLS und behob die verbleibenden Probleme noch am selben Abend. Es wurden keine Anzeichen für unbefugten Zugriff in den Supabase-Protokollen gefunden. Das Problem wurde eingedämmt, bevor es zu einem Vorfall wurde.


So überprüfen Sie Ihre eigene Supabase-Anwendung

Wenn Sie eine Supabase-gestützte Anwendung betreiben, finden Sie hier einen schnellen Selbst-Audit, den Sie in fünf Minuten durchführen können:

  1. Öffnen Sie das Supabase-Dashboard → Tabellen-Editor. Jede Tabelle ohne grünes Schild-Symbol hat RLS deaktiviert. Wenn diese Tabelle Benutzerdaten enthält, ist sie wahrscheinlich offengelegt.
  2. Öffnen Sie die Entwicklertools Ihres Browsers in Ihrer Produktions-App → Registerkarte „Netzwerk“ → filtern Sie nach Ihrer Supabase-Projekt-URL. Suchen Sie nach Anfragen an /rest/v1/[tablename]?select=*. Wenn Sie Anfragen sehen, die viele Datensätze zurückgeben, prüfen Sie, ob diese auf den authentifizierten Benutzer beschränkt sein sollten.
  3. Überprüfen Sie Ihren E-Mail-Verifizierungsablauf. Registrieren Sie ein neues Konto, überspringen Sie die Bestätigungs-E-Mail und versuchen Sie, direkt auf geschützte Teile Ihrer Anwendung zuzugreifen. Wenn Sie geschützte Funktionen erreichen können, ohne Ihre E-Mail zu bestätigen, erzwingt Ihr Backend die Verifizierung nicht.
  4. Überprüfen Sie Ihre Export-/Download-Endpunkte. Jeder Endpunkt, der eine Benutzer-ID als Parameter akzeptiert, sollte diese mit dem JWT des authentifizierten Benutzers abgleichen. Wenn der Parameter frei ausgetauscht werden kann, um auf die Daten eines anderen Benutzers zuzugreifen, handelt es sich um eine IDOR.

Diese vier Prüfungen dauern weniger als zehn Minuten und decken die häufigsten Supabase-Sicherheitslücken ab, die wir in Produktionsanwendungen sehen.


Das übergeordnete Muster

Diese Fallstudie ist nicht ungewöhnlich. Sie ist repräsentativ für das, was wir in der Mehrheit der Supabase-gestützten Anwendungen finden, die während eines Hackathons, eines schnellen Launch-Sprints oder von einem Solo-Gründer ohne Sicherheitshintergrund entwickelt wurden.

Die Kombination aus schnellen Tools, exzellenter Entwicklererfahrung und öffentlichen Standardeinstellungen, die Benutzerfreundlichkeit über Sicherheit stellen, führt dazu, dass viele Anwendungen mit diesen Lücken ausgeliefert werden. Die Lücken sind behebbar – oft in Minuten, selten mehr als eine SQL-Richtlinie oder eine einzeilige Middleware-Prüfung erfordernd. Der schwierige Teil ist, überhaupt zu wissen, dass sie existieren.

Das Supabase-Team hat erhebliche Arbeit geleistet, um RLS im Dashboard und in der Dokumentation stärker hervorzuheben. Doch die Kluft zwischen "die Dokumentation empfiehlt die Aktivierung" und "jede Produktions-App hat es tatsächlich aktiviert" bleibt groß. Bis automatisiertes Sicherheitstesting fester Bestandteil der Standard-Start-Checkliste wird, wird sich dieses Muster immer wieder zeigen.

Frequently Asked Questions

Welche Arten von Sicherheitslücken erkennt Penetrify?

Penetrify erkennt alle OWASP-Top-10-Schwachstellenkategorien, darunter SQL-Injection, XSS, CSRF, IDOR, fehlerhafte Authentifizierung, Sicherheitsfehlkonfigurationen und die Offenlegung sensibler Daten. Es testet auch die API-Sicherheit, das Session-Management und häufige Fehlkonfigurationen in Supabase, Firebase und Bubble.

Wie lange dauert ein KI-Penetrationstest?

Ein Quick-Scan ist in 15–30 Minuten abgeschlossen. Ein Standard-Scan läuft 1–2 Stunden mit breiterer Abdeckung. Ein Deep-Scan kann für komplexe Anwendungen mehrere Stunden dauern.

Was enthält ein Penetrify-Bericht?

Jeder Bericht enthält eine Executive Summary, einen Gesamtsicherheitsscore, nach Schweregrad klassifizierte Befunde (Kritisch, Hoch, Mittel, Niedrig), schrittweise Reproduktionsschritte und konkrete Abhilfemaßnahmen – geschrieben für Entwickler, nicht für Compliance-Beauftragte.

Related articles

CI/CD-Penetration Testing: Wie man Sicherheit in jede Bereitstellung einbettet
Erfahren Sie, wie Sie Penetration Testing in Ihre CI/CD-Pipeline integrieren. Umfasst SAST, DAST, Qualitäts-Gates und KI-gestütztes Testen, ohne die Bereitstellung zu verlangsamen.
Autonomes OWASP Schwachstellen-Scanning: Wie KI regelbasierte Sicherheitstests ersetzt
Erfahren Sie, wie autonome OWASP-Schwachstellenscans KI nutzen, um über den reinen Signaturabgleich hinauszugehen. Behandelt die OWASP Top 10 2025, agentisches Testen und warum regelbasierte Scanner nicht ausreichen.
Simulation mehrstufiger Angriffsketten: Warum das Scannen einzelner Schwachstellen nicht ausreicht
Erfahren Sie, wie die Simulation mehrstufiger Angriffsketten die verketteten Exploits findet, die Schwachstellenscanner übersehen. Praxisbeispiele, MITRE ATT&CK-Mapping und Implementierungsleitfaden.

Explore more

Compare alternatives →Security glossary →CI/CD integration →Security statistics →
Zurück zum Blog