// docs / baas security / supabase service role exposure
Clau de rol de servei de Supabase exposada a JavaScript: què significa i com detectar-la
La clau de rol de servei de Supabase és la clau mestra de la teva base de dades. Qui la tingui se salta la seguretat a nivell de fila, pot llegir cada columna de cada taula i pot escriure o esborrar el que vulgui. Està dissenyada per viure exclusivament en codi del costat del servidor — mai al navegador. Quan una eina de codificació amb IA l'envia al bundle de JavaScript, la teva base de dades queda, en efecte, pública. Aquest article explica la forma del JWT que identifica una clau filtrada, els tres patrons d'eines d'IA que produeixen la fuita, què fer en la primera hora després de la detecció i com escanejar-la automàticament abans que ho facin els usuaris.
Què és la clau de rol de servei
Supabase emet dues claus diferents per a cada projecte: la clau anon (també anomenada clau publicable en projectes més nous) i la clau service_role. Totes dues són JSON Web Tokens signats amb el secret JWT del teu projecte. La diferència és el claim role incorporat al payload del JWT — anon per a la clau pública, service_role per a la clau mestra. PostgREST, Supabase Storage i Supabase Auth passen a un mode de saltar-s'ho-tot quan veuen el claim service_role.
Descodifica qualsevol clau de Supabase a jwt.io i mira el payload. La forma d'un JWT de rol de servei és inconfusible:
Payload descodificat d'un JWT de rol de servei (mostrat com a bloc ressaltat a sota).
{
"iss": "supabase",
"ref": "[project-ref]",
"role": "service_role",
"iat": 1700000000,
"exp": 2000000000
}Els projectes Supabase més nous emeten claus de tipus secret amb el prefix sb_secret_ en lloc d'un JWT. El comportament és idèntic — qualsevol cosa que contingui sb_secret_ en un bundle públic és igual de catastròfica.
Com les eines de codificació amb IA filtren la clau de rol de servei
Hem vist els mateixos tres patrons en milers d'aplicacions generades amb IA. Cadascun comença amb un desenvolupador demanant ajuda a una eina d'IA i acaba amb la clau de servei incrustada en un bundle.
Patró 1: fitxer .env únic amb prefix NEXT_PUBLIC_
El desenvolupador demana a l'eina d'IA que "configuri Supabase" i accepta un sol .env amb totes dues claus. L'eina d'IA — entrenada amb un corpus on la majoria de variables d'entorn s'exposen via NEXT_PUBLIC_* — prefixa totes dues amb NEXT_PUBLIC_. Next.js incrusta qualsevol cosa que coincideixi amb aquest prefix al bundle client en temps de compilació. Publiques a Vercel i la clau de servei queda dins main.[hash].js.
Patró 2: clau incorrecta a la crida createClient
El desenvolupador enganxa totes dues claus en un fitxer config.ts generat per la IA, i la IA omple per error la crida createClient() del costat del navegador amb process.env.SUPABASE_SERVICE_ROLE_KEY. La compilació porta la variable i el JWT acaba al bundle.
Patró 3: clau de rol de servei incrustada en scripts de seed
El desenvolupador demana a l'eina d'IA que escrigui un script per poblar la base de dades. La IA incrusta la clau de rol de servei directament al fitxer (en lloc de llegir-la de l'entorn), confirma el fitxer al repositori, i el repositori públic de GitHub o la ruta /scripts/seed.js de l'aplicació desplegada ara està servint la clau.
Com detecta la fuita l'escaneig de bundle de FixVibe
La comprovació de secrets en bundle de FixVibe descarrega cada fitxer JavaScript referenciat per l'aplicació desplegada — chunks d'entrada, chunks de càrrega diferida, web workers, service workers — i els passa per un detector que descodifica qualsevol cosa que coincideixi amb la forma de JWT (eyJ[base64-header].eyJ[base64-payload].[signature]). Si el payload descodificat conté "role": "service_role", l'escaneig ho reporta com a troballa crítica amb la ruta del fitxer i la línia exacta on apareix la clau. La mateixa comprovació també detecta el patró més nou sb_secret_* per prefix.
L'escaneig mai s'autentica amb la clau descoberta. Identifica la forma i informa de la fuita — fer servir la clau per demostrar l'explotabilitat seria un accés no autoritzat a la teva base de dades. La prova és al mateix payload del JWT.
Detectada — què fer en la primera hora
Una clau de rol de servei filtrada és una emergència en temps d'execució. Assumeix que la clau ha estat extreta — els atacants monitoritzen bundles públics en temps real. Tracta la base de dades com a compromesa fins que hagis rotat la clau i auditat l'activitat recent.
- Rota la clau immediatament. Al panell de Supabase, ves a Project Settings → API → Service role key → Reset. La clau antiga queda invalidada en segons. Qualsevol codi del costat del servidor que faci servir la clau s'ha d'actualitzar i redesplegar abans que la rotació es faci efectiva.
- Audita l'activitat recent de la base de dades. Obre Database → Logs al panell. Filtra pels darrers 7 dies. Cerca consultes
SELECT *inusuals contra taules amb PII, instruccionsUPDATEoDELETEgrans i sol·licituds des d'IPs fora de la teva infraestructura coneguda. Supabase registra la capçalerax-real-ipa cada sol·licitud. - Comprova els objectes d'emmagatzematge. Visita Storage → Logs i revisa les descàrregues de fitxers recents. Una clau de rol de servei filtrada també atorga accés de saltar-s'ho-tot als contenidors privats.
- Elimina la clau del control de versions. Fins i tot després de la rotació, deixar el JWT al teu historial de git significa que es pot descobrir al repositori públic. Fes servir
git filter-repoo BFG Repo-Cleaner per netejar-lo de l'historial, i després fes force-push (avisa abans els col·laboradors). - Torna a escanejar després de la correcció. Executa un nou escaneig de FixVibe contra l'aplicació redesplegada. La troballa de secrets en bundle hauria de desaparèixer. Confirma que no queda cap JWT
service_roleni cap cadenasb_secret_*en cap chunk.
Prevenir la fuita des de l'inici
La correcció estructural és disciplina de nomenclatura més mesures de seguretat a nivell d'eines:
- No prefixis mai la clau de servei amb
NEXT_PUBLIC_*,VITE_*ni cap altre prefix que incrusti al bundle. La convenció de nomenclatura és el límit — tots els frameworks la respecten. - Mantén la clau de servei completament fora del
.envde la màquina del desenvolupador. Llegeix-la d'un gestor de secrets (Doppler, Infisical, variables d'entorn xifrades de Vercel) al desplegament, mai la confirmis localment. - <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.
- Afegeix una porta de CI que escanegi la sortida de la compilació. Després de
next build, fes grep a la sortida de.next/static/chunks/per la cadenaservice_role. Falla la compilació si hi ha alguna coincidència.
# 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 1Preguntes freqüents
Amb quina rapidesa troben els atacants claus de rol de servei de Supabase filtrades?
Els escàners de bundles públics rastregen nous desplegaments en pocs minuts. Investigadors han documentat exploits funcionals contra nous projectes de Supabase en menys d'una hora des del primer desplegament. Tracta qualsevol exposició de rol de servei com una finestra de 60 minuts, no de 60 dies.
N'hi ha prou amb rotar la clau o he d'assumir exfiltració de dades?
La rotació invalida la clau filtrada però no desfà les dades ja extretes. Si les teves taules contenen PII, dades de pagament o qualsevol dada regulada, pots tenir una obligació de notificació sota el RGPD (72 hores), la CCPA o la HIPAA. Audita els registres i consulta el teu assessor legal si l'auditoria mostra accés sospitós.
Em pot protegir RLS si es filtra la clau de rol de servei?
No. La seguretat a nivell de fila és saltada totalment pel claim service_role. Això és per disseny — la clau existeix precisament per permetre que el codi del backend salti RLS per a operacions d'administració. La mitigació és assegurar-se que la clau no arriba mai a un context on un atacant pugui llegir-la.
Això s'aplica al nou model de clau publicable / secreta de Supabase (<code>sb_publishable_</code> / <code>sb_secret_</code>)?
Sí — classe de risc idèntica. La clau sb_secret_* és el nou format de clau secreta que substitueix el JWT de rol de servei en projectes més nous. Qualsevol cosa que contingui sb_secret_* en un bundle és igual de catastròfica que un JWT de rol de servei filtrat. El detector de secrets en bundle de FixVibe coincideix amb totes dues formes.
I la clau anon / publicable — és segura al bundle?
Sí, per disseny. La clau anon està pensada per viure al navegador i és la que fa servir cada client web de Supabase. La seva seguretat depèn totalment que RLS estigui ben configurat a cada taula pública. Vegeu l'article Escàner de RLS de Supabase per saber què comprovar.
Següents passos
Executa un escaneig de FixVibe contra el teu URL de producció — la comprovació de secrets en bundle és gratuïta, sense registre, i informa de l'exposició de service_role en menys d'un minut. Combina-ho amb l'article Escàner de RLS de Supabase per verificar que la capa RLS fa la seva feina, i la Llista de comprovació de seguretat de contenidors de Supabase Storage per blindar l'accés als fitxers. Per saber per què les eines d'IA generen aquesta classe de fuita de manera tan fiable, llegeix Per què les eines de codificació amb IA deixen mancances de seguretat.
