Zum Inhalt springen
← Alle Beiträge

4. September 2026

Du versteckst den falschen Schlüssel

Der öffentliche Supabase-Schlüssel gehört ins Frontend, der ist mit Absicht öffentlich. Der geheime umgeht jede Policy. Vier Suchbefehle, die zeigen, ob er irgendwo gelandet ist, wo er nicht hingehört.

Jemand postet in einer Community einen Screenshot vom Network-Tab. Der Supabase-Schlüssel steht offen im Request, für jeden Besucher lesbar. Die Frage darunter: wie kriege ich den da raus. Die Antworten: Proxy bauen, eine Server-Route davor, den Schlüssel in eine Edge Function schieben.

Der ganze Aufwand ist umsonst. Der Schlüssel gehört genau dahin.

Der öffentliche Schlüssel ist zum Veröffentlichen da

Supabase hat ihn umbenannt, von anon zu “publishable key”. Der neue Name sagt es direkt. Die Doku schreibt, dass dieser Schlüssel in Umgebungen läuft, in denen sich überhaupt kein Geheimnis schützen lässt: Webseiten, Mobile Apps, CLIs. Jeder zieht ihn aus dem Quelltext oder aus dem gebauten Bundle. Das ist eingeplant.

Er identifiziert dein Projekt. Er entscheidet nichts. Was ein Besucher sehen darf, hängt an seinem Token und an deinen Policies. Wer den öffentlichen Schlüssel versteckt, ist an der falschen Stelle nervös. Die Stelle, an der es wirklich klemmt, ist die Policy: RLS an heißt nicht abgesichert.

Der andere Schlüssel im selben Dashboard

Direkt daneben liegt der zweite. Früher service_role, heute sb_secret_.... Der hat in Postgres das Attribut BYPASSRLS. Supabase beschreibt das als “skipping any and all Row Level Security policies you attach”. Jede. Auch die, an der du gestern eine Stunde gesessen hast.

Damit ist die Regel kurz: Der Schlüssel landet auf einem Server, den du kontrollierst, und sonst nirgends. Die Doku formuliert es härter als ich: “Never use in a browser, even on localhost.”

Beim Vibe Coding legt den niemand absichtlich ins Frontend. Er rutscht dahin. Ein Feature funktioniert nicht, die KI vermutet ein Rechteproblem, du gibst ihr den geheimen Schlüssel zum Testen, sie schreibt ihn in eine Datei. Das Feature läuft. Die Datei bleibt.

Der Handgriff: such ihn

Zehn Minuten. Du brauchst den geheimen Schlüssel selbst, den holst du im Dashboard unter Settings → API Keys. Einmal in eine Shell-Variable, dann laufen alle Befehle dagegen:

KEY='<hier der geheime Schlüssel>'

1. Das gebaute Bundle. Was hier drinsteht, lädt jeder Besucher herunter.

npm run build
grep -rlF "$KEY" dist .next build 2>/dev/null
grep -rl "sb_secret_" dist .next build 2>/dev/null

Keine Ausgabe ist das gute Ergebnis. Jeder Treffer heißt: ausgeliefert.

2. Die Git-History. Eine .env aus dem Repo zu löschen entfernt sie nicht aus der Vergangenheit.

git log --all -S "$KEY" --oneline
git log --all --name-only --pretty=format: -- '*.env*' | sort -u

Der erste Befehl zeigt jeden Commit, in dem der Schlüssel auftaucht oder verschwindet. Der zweite listet alle env-Dateien, die jemals eingecheckt waren.

3. Die Präfix-Falle. In Next.js wird jede Variable mit dem Präfix NEXT_PUBLIC_ beim Build fest in das JavaScript geschrieben, das an den Browser geht. Next.js sagt das klar: der Wert wird “inlined into any JavaScript sent to the browser”. Bei Vite macht VITE_ dasselbe. Ein Schlüssel hinter so einem Präfix ist öffentlich, egal wie er heißt.

grep -rnE "(NEXT_PUBLIC|VITE|PUBLIC)_[A-Z_]*(SERVICE|SECRET|ADMIN)" . \
  --exclude-dir=node_modules --exclude-dir=.git

4. Die Logs. Ein console.log in einer Edge Function schreibt in den Log-Viewer, und der Eintrag bleibt dort liegen.

grep -rnE "console\.(log|error)[^)]*(env|KEY|SECRET|SERVICE_ROLE)" \
  supabase/functions src app --exclude-dir=node_modules 2>/dev/null

Der schlimmste Fund ist console.log(Deno.env.toObject()). Das ist ein bequemer Debug-Griff und kippt den kompletten Schlüsselbund ins Log.

Wenn einer der vier Befehle etwas findet

Dann ist der Schlüssel verbrannt und du tauschst ihn aus. Bei den neuen Schlüsseln geht das im Dashboard: neuen geheimen Schlüssel anlegen, überall eintragen, erst danach den alten löschen. Supabase weist darauf hin, dass Löschen endgültig ist.

Hängst du noch am alten service_role-Schlüssel, ist der Weg länger. Supabase schreibt, dass sich die Legacy-Schlüssel nicht mehr rotieren lassen. Raus kommst du über die Migration auf publishable und secret. Die alten Schlüssel laufen ohnehin Ende 2026 aus, das Thema steht also sowieso auf deiner Liste.

Drei Stellen, die kein grep findet

Der Chat mit der KI. Beim Debuggen kippst du deine .env in den Prompt, oder du schickst einen Screenshot vom Dashboard mit sichtbarem Schlüssel. Der liegt jetzt in einem Transkript, über das du nicht bestimmst. Nach so einem Moment tauschst du ihn, auch wenn nichts Sichtbares passiert ist. Der Tausch kostet fünf Minuten.

Das Build-Skript. Ein echo zur Fehlersuche in der Pipeline, ein Deploy-Schritt, der die Umgebung ausgibt: der Wert steht im Build-Log, und wer Zugriff auf das Projekt hat, liest ihn mit. Such in deinen Workflow-Dateien nach echo und env.

Die Datei, die du für Server-Code hältst. In Next.js reicht ein "use client" oben in der Datei oder ein Import aus einer Client-Komponente, und der Code wandert ins Bundle. Deshalb ist Schritt 1 der wichtigste von allen. Deine Ordnerstruktur ist eine Absicht, der Build ist das Ergebnis. Geprüft wird das Ergebnis.

Wo es danach weitergeht

Die vier Befehle finden den Schlüssel dort, wo er am häufigsten landet. Sie sind kein vollständiges Sicherheitsbild. Wer welche Rechte im Projekt hat, welche Edge Function mit welchem Schlüssel arbeitet, welche Tabelle über eine View trotzdem offen liegt: das steht auf anderen Blättern.

Im Supabase-Guide liegt die geordnete Aufstellung, von den Schlüsseln über die Policies bis zu den Stellen, an denen Projekte in Produktion kippen. Der Handgriff hier funktioniert auch ohne. Wenn du diese Woche nur eine Sache machst, dann npm run build und einmal grep.

Michael Schreier
Michael Schreier

Diplom-Informatiker · 25 Jahre Entwicklung · LinkedIn

supabasesicherheitvibe-codingki
praxis-guides
$ guide --open "Supabase Best Practice"
[i] RLS, Auth und Realtime stehen so, dass dein Projekt in Produktion nicht an den bekannten Stellen umkippt.

PDF plus Beispiele · 197 € · framework-unabhängig

Supabase Best Practice
Michael Schreier

Fragen zum Thema?

Schreib mir — ich freue mich auf den Austausch.