En resumen
La anon key, ahora llamada publishable key, está hecha para ser pública: corresponde al rol anon o authenticated, y sus políticas RLS deciden qué ve. La service role key, ahora secret key, corresponde a service_role, que se salta RLS por completo. En mi tabla de prueba local con RLS activado y sin política, la clave pública obtuvo 0 filas y la secreta las 3. Ponga la publishable key en el navegador, mantenga la secret key en un servidor y rótela si alguna vez se publicó.
Soy Denys, ingeniero full-stack y de IA. Una secret key filtrada es lo primero que busco cuando heredo una app de Supabase, porque con ella cualquier otra protección es decoración. Este artículo explica qué abre cada clave, con las peticiones que ejecuté para comprobarlo.
¿Qué es la anon key de Supabase?
La anon key identifica a su app, no a su usuario. Toda petición de un navegador o de una app móvil la lleva, así que tiene que ser pública: cualquiera puede leerla en el código fuente de la página. Una petición con solo esta clave se ejecuta como el rol de Postgres anon. Cuando un usuario inicia sesión con Supabase Auth, la misma clave viaja con el token del usuario y la petición se ejecuta como authenticated. Sus políticas RLS están escritas para esos dos roles.
Supabase está cambiando el nombre de las claves. La guía de API keys llama a las nuevas publishable (sb_publishable_…) y secret (sb_secret_…), y da por obsoletas las antiguas anon y service_role, basadas en JWT, a finales de 2026. Los roles que hay detrás siguen siendo los mismos.
| Clave | Nombre antiguo | Rol de Postgres | ¿Se aplica RLS? | Dónde va |
|---|---|---|---|---|
Publishable sb_publishable_… |
anon key |
anon, o authenticated con un token de usuario |
Sí | Navegador, app móvil, cualquier cosa que usted distribuya |
Secret sb_secret_… |
service_role key |
service_role |
No, el rol tiene BYPASSRLS |
Solo servidor, Edge Function o tarea programada |
¿Es seguro exponer la anon key de Supabase?
Sí, si todas las tablas, vistas y funciones a las que llega están protegidas. La clave en sí no concede nada especial; los grants y las políticas de su esquema lo deciden todo. Lo comprobé en un stack local de Supabase (CLI 2.109.1, Postgres 17.6) con una tabla de tres pedidos falsos:
| Estado de la tabla | Publishable key | Secret key |
|---|---|---|
| RLS desactivado | Las 3 filas, y un insert devolvió 201 Created |
Las 3 filas |
| RLS activado, sin política | [] |
Las 3 filas |
RLS activado, política using (true) |
Las 3 filas | Las 3 filas |
Sin grant para anon |
42501 permission denied, con una pista que nombra el GRANT que falta |
Las 3 filas |
Así que la publishable key es tan segura como su tabla más débil. Una tabla sin RLS, o con una política que permite todas las filas, la lee cualquiera que abra DevTools. Ese es el hueco detrás de CVE-2025-48757, donde 170 de 1.645 apps de muestra de Lovable entregaban datos a la clave pública.
¿Qué es la service role key y por qué es peligrosa?
La secret key es la llave maestra. Se ejecuta como service_role, que tiene el atributo BYPASSRLS, así que ninguna política que usted escriba se le aplica jamás. En la última columna de la tabla anterior leyó las tres filas en todos los estados. La guía de Supabase enumera dónde corresponde: servidores que hacen sus propias comprobaciones de autorización, Edge Functions, tareas en segundo plano y herramientas de administración. Dos detalles de la guía importan en la práctica:
- La nueva secret key rechaza las peticiones desde un navegador: Supabase examina el
User-Agenty devuelve401. El JWT antiguo deservice_roleno tiene esa comprobación, así que una clave antigua filtrada funciona desde cualquier sitio. Mi stack local, que no tiene esa comprobación en el gateway, respondió con las 3 filas a un script que usaba la secret key. - Una secret key se salta RLS solo cuando la petición no lleva el token de un usuario. Con el token de un usuario con sesión iniciada, la petición se ejecuta bajo las políticas de ese usuario.
Una Edge Function que usa la secret key tiene que comprobar quién llama y filtrar ella misma por dueño o por empresa, porque nada por debajo lo hará.
¿Dónde se encuentran las claves?
En el Dashboard, abra el diálogo Connect de su proyecto para ver la URL y la publishable key, o Settings → API Keys para ver todas las claves, incluidas las antiguas. En local, supabase start y supabase status muestran una publishable key y una secret key. Guárdelas en variables de entorno: en Next.js, solo la publishable key puede llevar el prefijo NEXT_PUBLIC_, porque el bundler envía al navegador todo lo que lo lleve.
¿Qué hacer si la service role key se filtró?
Trátela como comprometida: cada fila de cada tabla pudo ser leída y escrita por quien la encontrara.
- Cree una nueva secret key, pase sus servidores a ella y después elimine la filtrada. Si la filtración fue de una
service_rolekey antigua, la salida es migrar a las claves nuevas: cree una publishable key y una secret key, cambie la app y después desactive las claves antiguas en Settings → API Keys, donde de otro modo siguen siendo válidas. - Busque
sb_secret_yservice_roleen el JavaScript compilado y en el historial de Git. El escaneo de Escape a 5.600 apps de vibe coding encontró más de 400 secretos expuestos, la mayoría en bundles de frontend. - Revise qué cambió mientras estuvo expuesta: usuarios nuevos, cambios de rol, filas borradas.
La Auditoría de seguridad de Supabase gratuita no lee su frontend, pero sí lee el lado de la base de datos del mismo problema: roles que eluden RLS, tablas con RLS desactivado, políticas que permiten todas las filas y columnas que parecen sensibles y que los visitantes anónimos pueden leer. Para comprobar qué alcanza en la práctica su clave pública, los pasos están en riesgos de seguridad del vibe coding, y la lista completa que ejecuto en una app está en mi lista de seguridad para apps Lovable.
¿No sabe qué clave envía su app?
Me gustaría echar un vistazo y comparar notas. Sin pitch.
Escríbame