Clave de Supabase expuesta: ¿cuál puede ir en el navegador?
La clave publicable de Supabase (sb_publishable_..., o la antigua anon) puede ir en el navegador, siempre que todas las tablas tengan RLS activo. La clave secreta (sb_secret_..., o la antigua service_role) nunca: ignora el RLS y abre toda la base de datos. Si la secreta se filtró, rótela antes que cualquier otra cosa.
Recomendación de Heartscale: busque la clave secreta en el código, en el build publicado y en el historial de git antes de concluir que no se filtró. Si aparece en alguno y la app ya tiene usuarios reales, rótela de inmediato y pida una revisión de las tablas y de los logs.
Las reglas de abajo siguen la documentación oficial de Supabase sobre API keys, revisada en octubre de 2026. Todo aquí aplica a su propio proyecto.
Las cuatro claves de Supabase
Supabase tiene dos sistemas de claves funcionando al mismo tiempo: el nuevo y el heredado. Cada uno tiene una clave pública y una secreta.
| Clave | Formato | ¿Puede ir en el navegador? | ¿Respeta el RLS? |
|---|---|---|---|
| Publicable | sb_publishable_... |
Sí | Sí |
anon (heredada) |
JWT largo, empieza con eyJ |
Sí | Sí |
| Secreta | sb_secret_... |
Nunca | No, lo ignora |
service_role (heredada) |
JWT largo, empieza con eyJ |
Nunca | No, lo ignora |
La documentación dice que la clave secreta no puede estar en el navegador, en una app distribuida, en un documento público ni en el control de versiones, ni siquiera en localhost. También indica que Supabase planea retirar las claves anon y service_role antes del fin de 2026.
Por qué la clave publicable puede quedar expuesta
Las apps hechas con Lovable, Bolt o Base44 suelen hablar con la base de datos desde el navegador. Para eso, la clave publicable va junto con el sitio y cualquier visitante puede verla.
Eso es lo esperado. Sin usuario con sesión, la clave publicable entra a la base con el rol anon. Con usuario con sesión, con el rol authenticated. Las políticas de RLS deciden qué puede leer o modificar cada rol. Por eso Supabase pide activar el RLS en todas las tablas antes de publicar.
El riesgo de la clave publicable está en las tablas sin RLS o con políticas demasiado abiertas. Rotar la clave no resuelve eso. El paso a paso está en Configurar RLS en Supabase y probar su app.
La clave secreta usa el rol service_role, que tiene el atributo BYPASSRLS. Las políticas nunca se aplican a ella. Quien tiene la clave secreta tiene la base de datos.
Paso 1: vea qué clave usa su código
Abra el repositorio de su app y busque las claves y los nombres de variable más comunes:
grep -rn --exclude-dir=node_modules -E "sb_secret_|service_role|SERVICE_ROLE_KEY|SUPABASE_SECRET" .
grep -rn --exclude-dir=node_modules -E "sb_publishable_|anon|PUBLISHABLE_KEY" .
Para cada resultado, pregúntese dónde se ejecuta ese código:
- Navegador: archivos en
src/, componentes de React y cualquier variable con prefijoVITE_. Vite advierte que las variablesVITE_quedan en el código del cliente y no deben guardar claves de API. Aquí solo puede aparecer la publicable. - Servidor: Edge Functions en
supabase/functions/, rutas de servidor y scripts que corren fuera del navegador. Aquí sí se puede usar la secreta, leída de una variable de entorno y nunca escrita en el archivo.
Si el resultado es un JWT largo que empieza con eyJ, compárelo con las claves de Settings > API Keys en el panel de Supabase. Así sabrá si es la anon o la service_role.
Revise también lo que de verdad llega al navegador. Haga el build de su app y busque en el resultado:
npm run build
grep -rn -E "sb_secret_|service_role" dist/
Cualquier resultado aquí es una clave secreta publicada en su sitio.
Una señal extra: Supabase revisa el User-Agent y devuelve 401 Unauthorized cuando se usa una clave secreta desde un navegador. Si su app recibe 401 en llamadas que deberían funcionar, verifique si la clave secreta terminó en el front. La documentación aclara que este bloqueo es solo una salvaguarda: la clave filtrada sigue sirviendo desde otras herramientas.
Paso 2: busque en el historial de git
Borrar la clave del archivo no la saca del historial. Busque en todas las ramas:
git log --all --oneline -S "sb_secret_"
git log --all --oneline -G "service_role|sb_secret_|SERVICE_ROLE_KEY"
-S muestra los commits que cambian la cantidad de veces que aparece el texto. -G muestra los commits cuyo diff agrega o quita una línea que coincide con el patrón (git log). Para ver el cambio de un commit encontrado, use git show <hash>.
Si la clave aparece en cualquier commit de un repositorio que alguna vez fue público, o compartido con alguien, trátela como filtrada.
Paso 3: se filtró la clave secreta, siga este orden
El orden viene de la documentación de Supabase. Rotar la clave va antes de limpiar el código, porque la clave anterior funciona hasta que usted la elimina.
- Corrija la causa. Saque la clave del front, de las variables
VITE_y de cualquier archivo versionado. Mueva la operación que la necesitaba a una Edge Function u otro código de servidor. - Cree una clave secreta nueva en Settings > API Keys. La documentación recomienda una clave secreta por componente del backend, para que una filtración futura obligue a rotar solo una.
- Reemplace la clave anterior en cada lugar que la usa: Edge Functions, servidor, tareas programadas e integraciones.
- Confirme que todos los componentes usan la clave nueva.
- Elimine la clave anterior. Eliminar una clave secreta no tiene vuelta atrás, así que hágalo solo después del paso 4. Para la
service_roleheredada, la opción es desactivarla en la misma sección, y eso se puede revertir.
Dos puntos sobre las claves heredadas:
- Crear claves nuevas no desactiva la
anonni laservice_role. Los dos sistemas funcionan a la vez hasta que usted desactive las heredadas. - En las Edge Functions, las variables
SUPABASE_ANON_KEYySUPABASE_SERVICE_ROLE_KEYtraen las claves heredadas. La documentación indica usarSUPABASE_SECRET_KEYSo el SDK@supabase/server. Si la app todavía usa laanonen el navegador, cámbiela por la publicable antes de desactivar las heredadas, para que la app no se detenga.
Paso 4: limpie el historial, si tiene sentido
GitHub también pone la rotación de la credencial como primer paso. Reescribir el historial viene después y tiene costo:
- los hashes de los commits cambian y quien tenga un clon antiguo puede volver a subir la clave;
- los forks y los pull requests antiguos conservan el contenido;
- la protección de rama contra force push debe apagarse por un tiempo.
Si la clave ya fue rotada y eliminada, el valor en el historial ya no abre nada. Muchos equipos se detienen aquí. Si decide limpiar, GitHub documenta el uso de git-filter-repo con la opción --sensitive-data-removal.
Paso 5: revise el RLS y el Security Advisor
La clave secreta ignora el RLS, así que las buenas políticas no protegieron nada mientras estuvo expuesta. Aun así, la rotación es un buen momento para revisar la clave publicable, que sigue en su sitio:
- confirme que todas las tablas expuestas tengan RLS activo y políticas por operación;
- recuerde que los permisos de la tabla (
grant) se revisan antes que el RLS; - abra el Security Advisor del proyecto y resuelva las alertas que muestre.
Paso 6: revise los logs del período
En el panel de Supabase, abra Logs y elija el tipo API Gateway (Logs). Ajuste el Time Range al período en que la clave estuvo expuesta y filtre por Method y Pathname. Busque escrituras y borrados que su app no hace, picos de volumen y tablas que nadie suele consultar. Use Download logs para guardar lo que encuentre.
La retención de los logs depende del plan. Hágalo pronto, antes de que desaparezcan los registros más antiguos.
Si los logs muestran acceso indebido a datos de personas y su app tiene usuarios en Brasil, puede tratarse de un incidente de seguridad según la LGPD, con plazo para comunicarlo a la ANPD. Vea LGPD para apps hechas con IA con usuarios en Brasil.
¿Y si solo se filtró la clave publicable?
Está hecha para ser pública, así que la filtración por sí sola no exige rotarla. Lo que importa es lo que alcanza. Consulte sus tablas con la clave publicable y sin usuario con sesión: todo lo que vuelva es lo que cualquier visitante ve. Si vuelven datos que no deberían, corrija el RLS o los permisos de la tabla.
En nuestras revisiones, hacemos esa consulta en cada tabla expuesta, primero con la clave publicable y sin sesión, y después como un usuario común que intenta leer datos de otro.
Para una revisión más amplia de su app, vea la página de seguridad de apps hechas con IA.
¿Hacerlo usted mismo o contratar?
Si la búsqueda no encontró la clave secreta, esta guía alcanza. La tabla muestra cuándo la rotación pide más cuidado.
| Situación | Camino |
|---|---|
| Solo la clave publicable está en el sitio y todas las tablas tienen RLS activo | Siga el paso 5 y pruebe las tablas sin sesión |
| La clave secreta se filtró y la app ya tiene usuarios reales | Rótela ahora, en el orden del paso 3, y pida una revisión de las tablas y los logs |
| La clave secreta la usan Edge Functions, tareas programadas e integraciones que usted no sabe enumerar | Llame a un equipo para mapear cada uso antes de eliminar la clave anterior |
| La app tiene usuarios reales y los logs muestran accesos que la app no hace | Solicite el diagnóstico de Heartscale y revise el plazo de comunicación de la LGPD si tiene usuarios en Brasil |
Solicite un diagnóstico de Heartscale
Nuestro equipo busca claves en el código, en el build publicado y en el historial de git, revisa dónde corre cada una y prueba el RLS de las tablas con la clave publicable. Si hay una clave secreta expuesta, usted recibe el orden de rotación para su caso y la corrección del código que dependía de ella. La revisión reduce el riesgo, pero no lo elimina.
El diagnóstico, a precio de lanzamiento, cuesta US$ 19 (antes US$ 79) y se descuenta si contrata la corrección. Solo trabajamos en apps de quien demuestra ser su dueño.