FixVibe

// docs / baas security / supabase service role exposure

Supabase service-role-nøgle eksponeret i JavaScript: hvad det betyder, og hvordan man finder den

Supabase service-role-nøglen er hovednøglen til din database. Enhver, der har den, omgår Row-Level Security, kan læse hver kolonne i hver tabel og kan skrive eller slette hvad som helst, de vælger. Den er designet til udelukkende at leve i server-side kode — aldrig i browseren. Når et AI-kodeværktøj sender den til JavaScript-bundtet, er din database i praksis offentlig. Denne artikel forklarer JWT-formen, der identificerer en lækket nøgle, de tre AI-værktøjsmønstre, der producerer lækagen, hvad man skal gøre i den første time efter detektion, og hvordan man scanner efter den automatisk, før brugerne gør det.

Hvad service-role-nøglen er

Supabase udsteder to forskellige nøgler for hvert projekt: anon-nøglen (også kaldet den publicerbare nøgle i nyere projekter) og service_role-nøglen. Begge er JSON Web Tokens signeret af dit projekts JWT-hemmelighed. Forskellen er role-claimet, der er indbagt i JWT-payloaden — anon for den offentlige nøgle, service_role for hovednøglen. PostgREST, Supabase Storage og Supabase Auth skifter alle til bypass-everything-tilstand, når de ser service_role-claimet.

Afkod enhver Supabase-nøgle på jwt.io, og se på payloaden. Formen på en service-role-JWT er umiskendelig:

Afkodet payload af en service-role-JWT (vist som en syntaks-fremhævet blok nedenfor).

json
{
  "iss": "supabase",
  "ref": "[project-ref]",
  "role": "service_role",
  "iat": 1700000000,
  "exp": 2000000000
}

Nyere Supabase-projekter udsteder hemmelighedslignende nøgler med præfikset sb_secret_ i stedet for en JWT. Adfærden er identisk — alt, der bærer sb_secret_ i et offentligt bundt, er lige så katastrofalt.

Sådan lækker AI-kodeværktøjer service-role-nøglen

Vi har set de samme tre mønstre på tværs af tusindvis af vibe-kodede apps. Hver enkelt starter med, at en udvikler beder et AI-værktøj om hjælp, og ender med, at service-nøglen er inlinet i et bundt.

Mønster 1: Enkelt .env-fil med NEXT_PUBLIC_-præfiks

Udvikleren beder AI-værktøjet om at "sætte Supabase op" og accepterer en enkelt .env med begge nøgler. AI-værktøjet — trænet på et korpus, hvor de fleste miljøvariabler eksponeres via NEXT_PUBLIC_* — sætter NEXT_PUBLIC_ foran begge. Next.js inliner alt, der matcher det præfiks, i klientbundtet på build-tidspunktet. Lever til Vercel, og service-nøglen er i main.[hash].js.

Mønster 2: Forkert nøgle i createClient-kald

Udvikleren indsætter begge nøgler i en config.ts-fil, som AI'en genererede, og AI'en udfylder browser-siden createClient()-kaldet med process.env.SUPABASE_SERVICE_ROLE_KEY ved en fejl. Buildet trækker variablen ind, og JWT'en lander i bundtet.

Mønster 3: Service-role-nøgle hardkodet i seed-scripts

Udvikleren beder AI-værktøjet om at skrive et script, der seeder databasen. AI'en hardkoder service-role-nøglen direkte i filen (i stedet for at læse fra miljø), committer filen til repositoriet, og det offentlige GitHub-repo eller den deployede apps /scripts/seed.js-rute serverer nu nøglen.

Sådan opdager FixVibe-bundtscanningen lækagen

FixVibes bundle-secrets-check downloader hver JavaScript-fil, der refereres af den deployede app — entry-chunks, lazy-loaded chunks, web workers, service workers — og kører dem gennem en detektor, der afkoder alt, der matcher JWT-formen (eyJ[base64-header].eyJ[base64-payload].[signature]). Hvis den afkodede payload indeholder "role": "service_role", rapporterer scanningen det som et kritisk fund med filstien og den nøjagtige linje, hvor nøglen optræder. Den samme check matcher også det nyere sb_secret_*-mønster efter præfiks.

Scanningen autentificerer sig aldrig med den opdagede nøgle. Den identificerer formen og rapporterer lækagen — at bruge nøglen til at bevise udnyttelse ville være uautoriseret adgang til din database. Beviset ligger i selve JWT-payloaden.

Detekteret — hvad man gør i den første time

En lækket service-role-nøgle er en runtime-nødsituation. Antag, at nøglen er blevet skrabet — angribere overvåger offentlige bundter i realtid. Behandl databasen som kompromitteret, indtil du har roteret nøglen og revideret nylig aktivitet.

  1. Roter nøglen straks. I Supabase Dashboard, gå til Project Settings → API → Service role key → Reset. Den gamle nøgle ugyldiggøres inden for sekunder. Enhver service-side kode, der bruger nøglen, skal opdateres og redeployes, før rotationen lander.
  2. Revider nylig databaseaktivitet. Åbn Database → Logs i dashboardet. Filtrer på de seneste 7 dage. Kig efter usædvanlige SELECT *-forespørgsler mod tabeller med PII, store UPDATE- eller DELETE-sætninger og anmodninger fra IP'er uden for din kendte infrastruktur. Supabase logger x-real-ip-headeren på hver anmodning.
  3. Tjek storage-objekter. Besøg Storage → Logs og gennemgå nylige fildownloads. En lækket service-role-nøgle giver bypass-everything-adgang også til private buckets.
  4. Fjern nøglen fra kildekontrol. Selv efter rotation betyder det, at JWT'en bliver i din git-historik, at den kan findes i det offentlige repo. Brug git filter-repo eller BFG Repo-Cleaner til at fjerne den fra historikken, og force-push derefter (advar samarbejdspartnere først).
  5. Scan igen efter fix. Kør en frisk FixVibe-scanning mod den redeployede app. Bundle-secrets-fundet bør forsvinde. Bekræft, at ingen service_role-JWT og ingen sb_secret_*-streng forbliver i nogen chunk.

Forebyggelse af lækagen i første omgang

Den strukturelle løsning er navngivningsdisciplin plus værktøjsniveauguardrails:

  • Sæt aldrig service-nøglen med NEXT_PUBLIC_*, VITE_* eller noget andet bundt-inlining-præfiks. Navngivningskonventionen er grænsen — hvert framework respekterer den.
  • Hold service-nøglen helt ude af .env på udviklermaskinen. Læs den fra en hemmelighedshåndtering (Doppler, Infisical, Vercel krypterede env-variabler) ved deploy, commit den aldrig lokalt.
  • <strong>Mark every Supabase client construction with explicit context.</strong> Files named <code>supabase/browser.ts</code> use the anon key; files named <code>supabase/server.ts</code> use the service-role key with <code>import 'server-only'</code> at the top. The <code>server-only</code> import causes a build error if a client component tries to consume the module.
  • <strong>Add a pre-commit hook that greps for JWT-shaped strings.</strong> <code>git diff --staged | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'</code> catches both anon and service tokens before they leave your machine.
  • Tilføj en CI-gate, der scanner buildoutputtet. Efter next build, grep .next/static/chunks/-outputtet for strengen service_role. Fejl buildet, hvis noget matcher.
bash
# Pre-commit hook: refuse any staged JWT-shaped string.
git diff --staged \
  | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' \
  && echo "JWT detected in staged changes — refusing commit" \
  && exit 1

# CI gate: fail the build if "service_role" shipped to the static bundle.
grep -RE 'service_role|sb_secret_' .next/static/chunks/ \
  && echo "Service-role credential leaked into bundle" \
  && exit 1

Ofte stillede spørgsmål

Hvor hurtigt finder angribere faktisk lækkede Supabase service-role-nøgler?

Offentlige bundtscannere trawler nye deployments inden for minutter. Forskere har dokumenteret fungerende exploits mod nye Supabase-projekter på under en time fra første deploy. Behandl enhver service-role-eksponering som et 60-minutters vindue, ikke et 60-dages vindue.

Er det nok at rotere nøglen, eller skal jeg antage dataeksfiltration?

Rotation ugyldiggør den lækkede nøgle, men ophæver ikke data, der allerede er trukket ud. Hvis dine tabeller indeholder PII, betalingsdata eller andre regulerede data, kan du have en underretningsforpligtelse under GDPR (72 timer), CCPA eller HIPAA. Revider logfilerne, og konsulter juridisk rådgivning, hvis revisionen viser mistænkelig adgang.

Kan RLS beskytte mig, hvis service-role-nøglen lækker?

Nej. Row-Level Security omgås fuldstændigt af service_role-claimet. Det er ved design — nøglen eksisterer netop for at lade backend-kode springe RLS over for admin-operationer. Modforanstaltningen er at sikre, at nøglen aldrig når en kontekst, hvor en angriber kan læse den.

Gælder dette for den nye Supabase publicerbare / hemmelig-nøgle-model (<code>sb_publishable_</code> / <code>sb_secret_</code>)?

Ja — identisk risikoklasse. sb_secret_*-nøglen er det nye hemmelige nøgleformat, der erstatter service-role-JWT'en for nyere projekter. Alt, der bærer sb_secret_* i et bundt, er lige så katastrofalt som en lækket service-role-JWT. FixVibes bundle-secrets-detektor matcher begge former.

Hvad med anon-/publicerbare nøglen — er den sikker i bundtet?

Ja, ved design. Anon-nøglen er beregnet til at leve i browseren og er, hvad enhver Supabase-webklient bruger. Dens sikkerhed afhænger helt af, at RLS er korrekt konfigureret på hver offentlig tabel. Se artiklen Supabase RLS-scanner for, hvad der skal tjekkes.

Næste skridt

Kør en FixVibe-scanning mod din produktions-URL — bundle-secrets-checken er gratis, ingen tilmelding, og rapporterer service_role-eksponering på under et minut. Par dette med artiklen Supabase RLS-scanner for at verificere, at RLS-laget gør sit arbejde, og Supabase storage-bucket sikkerhedstjekliste for at låse filadgang ned. For baggrund om, hvorfor AI-værktøjer så pålideligt genererer denne lækageklasse, læs Hvorfor AI-kodeværktøjer efterlader sikkerhedshuller.

// scan din baas-overflade

Find den åbne tabel, før nogen anden gør det.

Indsæt en produktions-URL. FixVibe opregner de BaaS-udbydere, din app taler med, fingeraftrykker deres offentlige endpoints og rapporterer, hvad en uautentificeret klient kan læse eller skrive. Gratis, ingen installation, intet kort.

  • Gratis niveau — 3 scanninger/måned, intet kort ved tilmelding.
  • Passiv BaaS-fingeraftrykning — ingen domæneverifikation påkrævet.
  • Supabase, Firebase, Clerk, Auth0, Appwrite og flere.
  • AI-fix-prompts på hvert fund — indsæt tilbage i Cursor / Claude Code.
Kør en gratis BaaS-scanning

ingen tilmelding krævet

Supabase service-role-nøgle eksponeret i JavaScript: hvad det betyder, og hvordan man finder den — Docs · FixVibe