FixVibe

// docs / baas security / supabase service role exposure

Supabase service-role-nøkkel eksponert i JavaScript: hva det betyr og hvordan du finner den

Supabase service-role-nøkkelen er hovednøkkelen til databasen din. Enhver som har den, omgår Row-Level Security, kan lese hver kolonne i hver tabell, og kan skrive eller slette hva de vil. Den er designet for å leve utelukkende i serverside-kode — aldri i nettleseren. Når et AI-kodeverktøy sender den til JavaScript-bundlen, er databasen din i praksis offentlig. Denne artikkelen forklarer JWT-formen som identifiserer en lekket nøkkel, de tre AI-verktøy-mønstrene som produserer lekkasjen, hva du skal gjøre den første timen etter deteksjon, og hvordan du skanner etter den automatisk før brukerne gjør det.

Hva service-role-nøkkelen er

Supabase utsteder to distinkte nøkler for hvert prosjekt: anon-nøkkelen (også kalt den publiserbare nøkkelen i nyere prosjekter) og service_role-nøkkelen. Begge er JSON Web Tokens signert av prosjektets JWT-hemmelighet. Forskjellen er role-claimet bakt inn i JWT-payloaden — anon for den offentlige nøkkelen, service_role for hovednøkkelen. PostgREST, Supabase Storage og Supabase Auth bytter alle til bypass-everything-modus når de ser service_role-claimet.

Dekod en hvilken som helst Supabase-nøkkel på jwt.io og se på payloaden. Formen til en service-role-JWT er umiskjennelig:

Dekodet payload av en service-role-JWT (vist som en syntaks-uthevet blokk nedenfor).

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

Nyere Supabase-prosjekter utsteder secret-style-nøkler med prefikset sb_secret_ i stedet for en JWT. Atferden er identisk — alt som bærer sb_secret_ i en offentlig bundle er like katastrofalt.

Hvordan AI-kodeverktøy lekker service-role-nøkkelen

Vi har sett de samme tre mønstrene på tvers av tusenvis av vibe-kodede apper. Hvert av dem starter med at en utvikler ber et AI-verktøy om hjelp og ender med at service-nøkkelen er inlinet i en bundle.

Mønster 1: Enkel .env-fil med NEXT_PUBLIC_-prefiks

Utvikleren ber AI-verktøyet om å "sette opp Supabase" og aksepterer en enkelt .env med begge nøklene. AI-verktøyet — trent på et korpus der de fleste miljøvariabler eksponeres via NEXT_PUBLIC_* — prefikser begge med NEXT_PUBLIC_. Next.js inlinerer alt som matcher det prefikset i klientbundlen ved byggetidspunkt. Lever til Vercel, og service-nøkkelen ligger i main.[hash].js.

Mønster 2: Feil nøkkel i createClient-kall

Utvikleren limer inn begge nøklene i en config.ts-fil AI-en genererte, og AI-en fyller ut det nettleserside createClient()-kallet med process.env.SUPABASE_SERVICE_ROLE_KEY ved en feil. Byggingen henter inn variabelen, og JWT-en lander i bundlen.

Mønster 3: Service-role-nøkkel hardkodet i seed-skript

Utvikleren ber AI-verktøyet om å skrive et skript som seeder databasen. AI-en hardkoder service-role-nøkkelen direkte i filen (i stedet for å lese fra miljøet), committer filen til repoet, og det offentlige GitHub-repoet eller den deployede appens /scripts/seed.js-rute serverer nå nøkkelen.

Slik oppdager FixVibes bundle-skanning lekkasjen

FixVibes bundle-secrets-sjekk laster ned hver JavaScript-fil referert av den deployede appen — entry-chunks, lazy-lastede chunks, web workers, service workers — og kjører dem gjennom en detektor som dekoder alt som matcher JWT-formen (eyJ[base64-header].eyJ[base64-payload].[signature]). Hvis den dekodede payloaden inneholder "role": "service_role", rapporterer skanningen det som et kritisk funn med filstien og den eksakte linjen der nøkkelen vises. Samme sjekk matcher også det nyere sb_secret_*-mønsteret etter prefiks.

Skanningen autentiserer seg aldri med den oppdagede nøkkelen. Den identifiserer formen og rapporterer lekkasjen — å bruke nøkkelen for å bevise utnyttbarhet ville vært uautorisert tilgang til databasen din. Beviset ligger i selve JWT-payloaden.

Oppdaget — hva du skal gjøre den første timen

En lekket service-role-nøkkel er en runtime-nødssituasjon. Anta at nøkkelen har blitt skrapet — angripere overvåker offentlige bundles i sanntid. Behandle databasen som kompromittert til du har rotert nøkkelen og granska nylig aktivitet.

  1. Roter nøkkelen umiddelbart. I Supabase Dashboard, gå til Project Settings → API → Service role key → Reset. Den gamle nøkkelen invalideres innen sekunder. All serverside-kode som bruker nøkkelen må oppdateres og redeployes før rotasjonen lander.
  2. Granske nylig databaseaktivitet. Åpne Database → Logs i dashboardet. Filtrer på siste 7 dager. Se etter uvanlige SELECT *-spørringer mot tabeller med PII, store UPDATE- eller DELETE-utsagn, og requests fra IP-er utenfor din kjente infrastruktur. Supabase logger x-real-ip-headeren på hver request.
  3. Sjekke storage-objekter. Besøk Storage → Logs og gjennomgå nylige filnedlastinger. En lekket service-role-nøkkel gir bypass-everything-tilgang til private buckets også.
  4. Fjerne nøkkelen fra source control. Selv etter rotasjon betyr det at JWT-en ligger i git-historikken din at den er oppdagelig i det offentlige repoet. Bruk git filter-repo eller BFG Repo-Cleaner for å skrubbe den fra historikken, og deretter force-push (advar samarbeidspartnere først).
  5. Skanne på nytt etter fiks. Kjør en fersk FixVibe-skanning mot den redeployede appen. Bundle-secrets-funnet skal forsvinne. Bekreft at ingen service_role-JWT og ingen sb_secret_*-streng gjenstår i noen chunk.

Forebygging av lekkasjen i utgangspunktet

Den strukturelle fiksen er navnedisiplin pluss verktøynivå-rekkverk:

  • Aldri prefiks service-nøkkelen med NEXT_PUBLIC_*, VITE_* eller noe annet bundle-inlinende prefiks. Navnekonvensjonen er grensen — alle rammeverk respekterer den.
  • Hold service-nøkkelen helt utenfor .env på utviklermaskinen. Les den fra en hemmelighetsbehandler (Doppler, Infisical, Vercel krypterte env-vars) ved deploy, aldri commit den 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.
  • Legg til en CI-port som skanner byggeutgangen. Etter next build, grep .next/static/chunks/-utgangen etter service_role-strengen. La byggingen feile hvis noe 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 stilte spørsmål

Hvor raskt finner angripere faktisk lekkede Supabase service-role-nøkler?

Skannere av offentlige bundles tråler nye deployments innen minutter. Forskere har dokumentert fungerende utnyttelser mot nye Supabase-prosjekter på under en time fra første deploy. Behandle enhver service-role-eksponering som et 60-minutters vindu, ikke et 60-dagers.

Er det nok å rotere nøkkelen, eller må jeg anta dataeksfiltrering?

Rotasjon invaliderer den lekkede nøkkelen, men opphever ikke data som allerede er hentet ut. Hvis tabellene dine inneholder PII, betalingsdata eller andre regulerte data, kan du ha en meldeplikt under GDPR (72 timer), CCPA eller HIPAA. Granske loggene og rådfør deg med juridisk rådgiver hvis granskingen viser mistenkelig tilgang.

Kan RLS beskytte meg hvis service-role-nøkkelen lekker?

Nei. Row-Level Security omgås fullstendig av service_role-claimet. Det er ved design — nøkkelen finnes nettopp for å la backend-kode hoppe over RLS for admin-operasjoner. Avbøtningen er å sørge for at nøkkelen aldri når en kontekst der en angriper kan lese den.

Gjelder dette for den nye Supabase publiserbare/secret-nøkkel-modellen (<code>sb_publishable_</code> / <code>sb_secret_</code>)?

Ja — identisk risikoklasse. sb_secret_*-nøkkelen er det nye secret-nøkkel-formatet som erstatter service-role-JWT-en for nyere prosjekter. Alt som bærer sb_secret_* i en bundle er like katastrofalt som en lekket service-role-JWT. FixVibes bundle-secrets-detektor matcher begge formene.

Hva med anon-/publiserbar nøkkel — er den trygg i bundlen?

Ja, ved design. Anon-nøkkelen er ment å leve i nettleseren og er det enhver Supabase-webklient bruker. Sikkerheten avhenger helt og holdent av at RLS er riktig konfigurert på hver offentlige tabell. Se artikkelen Supabase RLS-skanner for hva du skal sjekke.

Neste steg

Kjør en FixVibe-skanning mot produksjons-URL-en din — bundle-secrets-sjekken er gratis, ingen registrering, og rapporterer service_role-eksponering på under et minutt. Par dette med artikkelen Supabase RLS-skanner for å verifisere at RLS-laget gjør jobben sin, og Sjekkliste for Supabase storage-bucket-sikkerhet for å låse ned filtilgang. For bakgrunn til hvorfor AI-verktøy genererer denne lekkasjeklassen så pålitelig, les Hvorfor AI-kodeverktøy etterlater sikkerhetshull.

// skann din baas-flate

Finn den åpne tabellen før noen andre gjør det.

Lim inn en produksjons-URL. FixVibe identifiserer BaaS-leverandørene appen din snakker med, fingeravtrykker deres offentlige endepunkter, og rapporterer hva en uautentisert klient kan lese eller skrive. Gratis, ingen installasjon, intet kort.

  • Gratisnivå — 3 skanninger/måned, intet kort ved registrering.
  • Passiv BaaS-fingeravtrykking — ingen domeneverifisering nødvendig.
  • Supabase, Firebase, Clerk, Auth0, Appwrite og flere.
  • AI-fiksforslag på hvert funn — lim tilbake i Cursor / Claude Code.
Kjør en gratis BaaS-skanning

ingen registrering nødvendig

Supabase service-role-nøkkel eksponert i JavaScript: hva det betyr og hvordan du finner den — Docs · FixVibe