Guía
¿Los datos de mi app en Supabase son públicos?
Son públicos si una tabla tiene apagada la seguridad por filas (RLS) o una política que deja leer a cualquiera. Tu app le entrega la clave publicable, la anon key en proyectos anteriores, a cada visitante, así que lo que esa clave pueda leer lo puede leer cualquiera. Empieza por el Security Advisor de tu panel de Supabase y luego prueba tu propio proyecto solo con esa clave.

Por qué la clave pública no es el problema
Supabase arma una API a partir de tu base de datos que el navegador llama directamente. La clave publicable está hecha para vivir en el navegador: la documentación de Supabase dice que es segura de exponer, porque solo alcanza lo que permite RLS. Si hiciste tu app con Lovable, Bolt u otra herramienta que la conectó a Supabase, todo esto te aplica.
Qué hace la seguridad por filas
RLS es una función de Postgres que le agrega una regla a cada consulta sobre una tabla. Se ven las filas para las que la regla da verdadero; las demás no. Con RLS activado y sin ninguna política, la clave publicable no lee nada. Activar RLS cierra la tabla, y tus políticas deciden qué se vuelve a abrir.
Los errores más comunes
- RLS apagado. El Security Advisor lo marca como error: cualquiera con la URL de tu proyecto puede leer, editar y borrar todas las filas.
- Una política que solo dice true. Una política de lectura para el rol anon o public (una política sin rol indicado aparece como public) con using (true) deja que cualquier visitante lea todas las filas. Sirve para una tabla de posiciones pública, no para clientes ni pedidos.
- Haber iniciado sesión cuenta como permiso. Una política para el rol authenticated sin revisar la fila deja que cualquier usuario con sesión lea las filas de todos. Si cualquiera puede registrarse, eso es cualquiera.
- Una política abierta que se quedó. Las políticas permisivas de una tabla se combinan con OR, así que una política abierta deja la tabla abierta aunque agregues otra estricta.
- Reglas basadas en los metadatos del usuario. Supabase advierte que una política construida sobre el claim user_metadata puede causar problemas de seguridad. Guarda los roles en una tabla tuya, protegida con sus propias políticas.
- Una vista que se salta RLS. Las vistas se saltan RLS por defecto. En Postgres 15 o posterior, créalas con security_invoker = true para que sigan las políticas de las tablas.
- La clave secreta dentro de la app. La clave secreta, service_role en proyectos anteriores, se salta todas las políticas. Si está en el código del navegador, tus políticas no protegen nada hasta que la rotes.
Cómo probar tu propio proyecto
Haz esto solo en tu propio proyecto. Nunca apliques estos pasos a la app de otra persona. Cada paso puede mostrar que algo está abierto. Ninguno puede mostrar que todo está cerrado: un resultado limpio solo quiere decir que ese paso no encontró nada, y no equivale a una auditoría de seguridad. El almacenamiento de archivos, las funciones de la base de datos y los esquemas distintos de public quedan fuera de esta guía.
- Abre el Security Advisor en el panel de Supabase y corrige cada error que muestre, empezando por "RLS Disabled in Public".
- En el editor de SQL, lista las tablas públicas con RLS apagado: select tablename from pg_tables where schemaname = 'public' and not rowsecurity;
- Lista tus vistas, porque no salen en la consulta anterior: select table_name from information_schema.views where table_schema = 'public'; y, para las vistas materializadas, select matviewname from pg_matviews where schemaname = 'public'; Una vista se salta RLS a menos que se haya creado con security_invoker = true, y una vista materializada guarda su propia copia de las filas, que las políticas de las tablas no filtran. Prueba todas con la petición de más abajo.
- Lista tus políticas y lee cada regla, las de insert, update y delete además de las de select, porque las dos peticiones de abajo solo prueban la lectura: select tablename, policyname, roles, cmd, qual, with_check from pg_policies where schemaname = 'public';
- Pregúntale a la API como lo haría un extraño, solo con la clave publicable, igual que en la guía rápida de Supabase: curl 'https://TU-PROYECTO.supabase.co/rest/v1/TU_TABLA?select=*' -H 'apikey: TU_CLAVE_PUBLICABLE'. Hazlo con cada tabla y cada vista que guarde datos privados. Si salen filas, cualquiera las puede leer. Ninguna otra respuesta prueba que la tabla está cerrada. Un error 'permission denied for table' (código 42501; en una vista dice 'for view') quiere decir que esa petición fue rechazada, y una que pida menos columnas podría no serlo. Una lista vacía sale de una tabla cerrada, de una vacía y de una que una política abre solo en parte. Si responde 'Invalid API key', la prueba no corrió: corrige la clave y repítela. Lo que la clave puede leer lo deciden las políticas que listaste arriba, así que la petición se suma a leerlas y no lo reemplaza.
- Después pregunta como un usuario con sesión. La petición anterior no detecta una política que deja a cualquier usuario con sesión leer todo, y las pantallas de tu app tampoco, porque normalmente solo piden las filas del usuario actual. Crea dos usuarios de prueba y dale a cada uno filas propias. Entra a tu app con el primero, abre las herramientas de desarrollador del navegador, busca en la pestaña Network una petición a la dirección /rest/v1/ de tu proyecto y copia el token de su encabezado Authorization, lo que va después de Bearer. Usa una petición hecha después de iniciar sesión: antes, el encabezado lleva la clave pública en lugar del token de un usuario.
- Repite el mismo curl con ese token y sin filtros en la dirección: -H 'Authorization: Bearer TOKEN_DEL_PRIMER_USUARIO'. Si salen filas del segundo, cualquier usuario con sesión las puede leer. La API limita cuántas filas devuelve una petición, así que pide también las filas del segundo usuario directamente, agregando &user_id=eq.ID_DEL_SEGUNDO_USUARIO con el nombre de tu propia columna: si sale alguna, quiere decir lo mismo. Si no salen las filas del primer usuario, o la respuesta dice que el token venció, la prueba no corrió como ese usuario: copia un token nuevo (dura una hora por defecto) y repítela. Repítelo con el segundo usuario. Ver solo tus propias filas muestra lo que estos dos usuarios pueden leer hoy en esa tabla, no que todas las políticas estén bien.
Dónde entra LOJIK
Estos pasos los puedes hacer tú. Si quieres una segunda mirada, la página de Rescate de LOJIK es para apps hechas con herramientas de IA que se quedaron a medias.
La página abre con un autodiagnóstico gratis. Sin iniciar sesión.
Cuándo LOJIK no es la opción adecuada
Probablemente LOJIK no sea la mejor opción si:
- Ya tienes un desarrollador o un equipo de seguridad que revisa tus políticas.
- Quieres que alguien pruebe un proyecto ajeno. Nadie debería hacerlo sin permiso por escrito de su dueño.
- Un cliente o un regulador te pide una auditoría formal de seguridad.
Preguntas
¿Es seguro que la anon key esté en el código de mi app?
Sí, si RLS está activado y tus políticas son correctas. La clave publicable, la anon key en proyectos anteriores, está hecha para ser pública y solo alcanza lo que permite RLS. La que nunca debe estar ahí es la clave secreta.
¿Activar RLS va a romper mi app?
Puede pasar, hasta que agregues políticas. Con RLS activado y sin políticas, la clave publicable no lee nada, así que las pantallas que leen esa tabla se quedan vacías. Agrega las políticas en el mismo cambio.
Hice mi app con Lovable. ¿Esto me aplica?
Si tu app guarda sus datos en Supabase, sí. Abre el proyecto de Supabase que usa tu app y haz las mismas revisiones.
Los nombres de producto pertenecen a sus dueños. LOJIK no tiene relación con ellos y los menciona solo para decir de qué herramienta se trata.
Fuentes
- Documentación de Supabase: Row Level Security
- Documentación de Supabase: Understanding API keys
- Documentación de Supabase: Advisors
- Documentación de Supabase: REST API
- Documentación de Supabase: guía rápida de la API
- Documentación de Supabase: JSON Web Tokens
- Documentación de Supabase: User sessions
- Documentación de PostgreSQL: CREATE POLICY
- Documentación de PostgreSQL: pg_tables
- Documentación de PostgreSQL: pg_policies
- Documentación de PostgreSQL: information_schema.views
- Documentación de PostgreSQL: pg_matviews
Revisado contra estas fuentes el 11 nov 2026.