// 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).
{
"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.
- 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.
- 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, storeUPDATE- ellerDELETE-sætninger og anmodninger fra IP'er uden for din kendte infrastruktur. Supabase loggerx-real-ip-headeren på hver anmodning. - 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.
- 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-repoeller BFG Repo-Cleaner til at fjerne den fra historikken, og force-push derefter (advar samarbejdspartnere først). - 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 ingensb_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
.envpå 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 strengenservice_role. Fejl buildet, hvis noget matcher.
# 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 1Ofte 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.
