// docs / baas security / supabase rls scanner
Escáner de RLS de Supabase: detecta tablas con seguridad a nivel de fila ausente o rota
La seguridad a nivel de fila (RLS) es lo único que se interpone entre los datos de tus clientes e internet cuando publicas una aplicación respaldada por Supabase. Las herramientas de codificación con IA generan código con forma de RLS que compila, se publica y filtra datos en silencio — tablas creadas sin RLS habilitado, políticas que leen pero nunca restringen, predicados que comparan una columna consigo misma. Este artículo muestra qué puede probar un escáner de RLS de Supabase desde el exterior, las cuatro formas de RLS rota que aparecen en aplicaciones generadas por IA y cómo escanear tu propio despliegue en menos de un minuto.
Qué puede probar un escaneo de RLS externo
Un escaneo de RLS pasivo se ejecuta contra el endpoint PostgREST que Supabase expone en https://[project].supabase.co/rest/v1/. Solo utiliza la clave anon publicable — la misma que usa tu navegador — y sondea los metadatos de listado de tablas, las lecturas anónimas y las escrituras anónimas. Nunca se autentica como usuario y nunca toca los privilegios de rol de servicio. Cualquier cosa que pueda hacer, un atacante no autenticado en internet también puede hacerla.
Desde fuera de la base de datos, un escáner puede confirmar lo siguiente con alta confianza:
- RLS está deshabilitado en una tabla. PostgREST devuelve filas para un
SELECTanónimo cuando RLS está desactivado o cuando una política lo permite. Cualquiera de los dos casos es un hallazgo. - El rol anónimo puede listar tablas. Un
GET /rest/v1/con la clave anon devuelve el esquema OpenAPI de toda tabla sobre la que el rolanontenga cualquier privilegio. Las aplicaciones generadas por IA con frecuencia otorganUSAGEsobre el esquema ySELECTsobre cada tabla, lo que expone el mapa completo del esquema incluso cuando RLS niega las lecturas reales. - El rol anónimo puede insertar. Un
POSTde sondeo con una conjetura sobre la forma de las columnas tendrá éxito si RLS no tiene una políticaINSERTque lo niegue — incluso siSELECTestá bloqueado. - La clave de rol de servicio está en el bundle del navegador. Adyacente a RLS: si un escáner encuentra
SUPABASE_SERVICE_ROLE_KEYo cualquier JWT conrole: service_roleen el bundle de JavaScript, RLS es irrelevante — quien posea esa clave puede saltarse cualquier política.
Qué no puede probar un escaneo externo
Sé honesto sobre los límites del escáner. Un escaneo de RLS externo no puede leer tu tabla pg_policies, tus archivos de migración ni el predicado exacto de ninguna política. Infiere a partir del comportamiento de caja negra, lo que significa que a veces reportará un hallazgo que resulta ser datos públicos intencionados (una tabla de newsletter de marketing, un catálogo público de productos). El reporte de FixVibe los marca como confianza media cuando el escáner no puede determinar la intención — revisa el nombre de la tabla y decide.
Las cuatro formas de RLS rota que producen las herramientas de IA
Cuando apuntas Cursor, Claude Code, Lovable o Bolt a Supabase, los mismos cuatro patrones de RLS rota emergen en miles de aplicaciones. Cada uno pasa la verificación de tipos, compila y se publica:
Forma 1: RLS nunca habilitado
El modo de fallo más común. La migración crea la tabla pero el desarrollador (o la herramienta de IA) olvida ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST sirve felizmente la tabla completa a cualquiera con la clave anon. Solución: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. FORCE no es opcional — sin él, el propietario de la tabla (y cualquier rol con propiedad de tabla) se salta RLS.
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;Forma 2: RLS habilitado, sin políticas
Un fallo más sutil. RLS está habilitado pero no se han escrito políticas. El predeterminado en PostgreSQL es denegar, por lo que los usuarios autenticados no ven nada — y el desarrollador añade USING (true) para que la aplicación funcione, lo que permite que todos lo lean todo. Solución: escribe una política que acote por auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); y una política INSERT/UPDATE/DELETE correspondiente.
CREATE POLICY "select_own"
ON public.[name]
FOR SELECT
USING (auth.uid() = user_id);Forma 3: La política compara la columna consigo misma
A copy-paste artefact. The developer writes <code>USING (user_id = user_id)</code> — which is always true — instead of <code>USING (auth.uid() = user_id)</code>. Type-checks pass; the policy permits every row. <strong>Fix:</strong> always compare a column to a function call (<code>auth.uid()</code>, <code>auth.jwt()->>'org_id'</code>, etc.), never to itself or to a constant.
Forma 4: Política en SELECT pero no en INSERT/UPDATE
El desarrollador bloquea las lecturas pero olvida las escrituras. Las políticas RLS son por comando. FOR SELECT solo protege las lecturas; un cliente anónimo todavía puede INSERT si ninguna política lo niega. Solución: escribe una política por comando, o usa FOR ALL con cláusulas explícitas USING y WITH CHECK.
Cómo funciona el escáner de RLS de Supabase de FixVibe
La verificación baas.supabase-rls se ejecuta en tres etapas, cada una con niveles de confianza explícitos:
- Etapa 1 — identificación. El escáner rastrea la aplicación desplegada, analiza su bundle de JavaScript y extrae la URL del proyecto Supabase y la clave anon de la configuración en tiempo de ejecución. Sin adivinanzas de DNS, sin fuerza bruta — lee lo mismo que lee el navegador.
- Etapa 2 — descubrimiento del esquema. Un único
GET /rest/v1/con la clave anon devuelve el esquema OpenAPI de cada tabla que el rol anon pueda ver. El escáner registra los nombres de las tablas pero no lee los datos de las filas en esta etapa. - Etapa 3 — sondeos de lectura y escritura. Para cada tabla descubierta, el escáner emite un
SELECTanónimo conlimit=1. Si se devuelven filas, RLS es permisivo. El escáner se detiene ahí — no enumera filas, no pagina, no modifica datos. Los sondeos INSERT están restringidos por la verificación de propiedad de dominio y opt-in explícito; nunca se ejecutan contra objetivos no verificados.
Cada hallazgo se entrega con la URL exacta de la solicitud, el estado de la respuesta, la forma de la respuesta (solo cabecera) y el nombre de la tabla. El prompt de corrección con IA al final del hallazgo es un bloque SQL listo para copiar y pegar que ejecutas en el editor SQL de Supabase.
Qué hacer cuando el escáner encuentra algo
Cada hallazgo de RLS es una emergencia en tiempo de ejecución. Los endpoints PostgREST públicos son escaneados por atacantes en cuestión de minutos. La secuencia de remediación es mecánica:
- Audita cada tabla. Ejecuta
SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';en el editor SQL de Supabase. Cualquier fila conrowsecurity = falsees un problema. - Habilita RLS en cada tabla pública. Por defecto, aplica
ENABLE ROW LEVEL SECURITYyFORCE ROW LEVEL SECURITYen cada tabla creada — conviértelo en una plantilla de migración. - Escribe políticas comando por comando. No uses
FOR ALL USING (true). Escribe políticas explícitas para SELECT, INSERT, UPDATE, DELETE — cada una acotada aauth.uid()o a una columna de org-id desdeauth.jwt(). - Verifica con una segunda cuenta. Regístrate como un usuario diferente, intenta leer los registros de otro usuario a través de la API REST directamente. Si la respuesta es
200, la política está rota. - Vuelve a escanear. Tras aplicar la corrección, ejecuta de nuevo un escaneo de FixVibe contra la misma URL. El hallazgo
baas.supabase-rlsdebería desaparecer.
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY rowsecurity, tablename;Cómo se compara esto con otros escáneres
La mayoría de herramientas DAST genéricas (Burp Suite, OWASP ZAP, Nessus) no saben qué es PostgREST. Rastrearán tu aplicación, ignorarán la ruta /rest/v1/ y reportarán las páginas HTML que sí entienden. Snyk y Semgrep son herramientas de análisis estático — encuentran archivos de migración en tu repositorio con llamadas RLS faltantes, pero no pueden demostrar que la base de datos desplegada esté mal configurada. FixVibe ocupa ese hueco: pasivo, consciente de BaaS, enfocado en lo que un atacante no autenticado puede demostrar desde la URL pública.
Preguntas frecuentes
¿Leerá o modificará el escáner mis datos?
No. Los escaneos pasivos emiten como máximo un SELECT ... limit=1 por tabla descubierta para confirmar si RLS permite lecturas anónimas. El escáner registra la forma de la respuesta, no el contenido de las filas. Los sondeos INSERT, UPDATE y DELETE están restringidos por la verificación de propiedad de dominio y nunca se ejecutan contra objetivos no verificados.
¿Funciona esto si mi proyecto de Supabase está pausado o en un dominio personalizado?
Los proyectos pausados devuelven 503 en cada solicitud — el escáner reporta el proyecto como inalcanzable. Los dominios personalizados funcionan siempre que la aplicación desplegada cargue el SDK cliente de Supabase en el navegador; el escáner extrae la URL del proyecto del bundle de cualquier modo.
¿Qué pasa si rotan mi clave anon o cambia mi clave publicable?
Vuelve a ejecutar el escaneo. El escáner extrae la clave del bundle actual en cada ejecución. La rotación solo invalida el reporte anterior, no el estado de las políticas de la base de datos.
¿El escáner comprueba el nuevo modelo de clave publicable de Supabase (<code>sb_publishable_*</code>)?
Sí. El detector reconoce tanto los JWT anon heredados como las claves más nuevas sb_publishable_* y las trata de forma idéntica — ambas están pensadas para ser públicas y ambas dejan a RLS como la única línea de defensa.
Próximos pasos
Ejecuta un escaneo gratuito de FixVibe contra tu URL de producción — la verificación baas.supabase-rls está habilitada en todos los planes, incluido el gratuito. Para una lectura más profunda sobre qué otras cosas pueden filtrarse desde un proyecto Supabase, consulta Clave de rol de servicio de Supabase expuesta en JavaScript y Lista de comprobación de seguridad de buckets de Supabase Storage. Para la vista general en todos los proveedores BaaS, lee Escáner de configuraciones erróneas de BaaS.
