Auditoría de Código Lovable: Problemas de Seguridad, Brechas RLS y Claves API Expuestas
Auditoría de Codebase de Lovable: Problemas de Seguridad, Brechas en RLS y Claves API Expuestas
Un cliente acudió a nosotros el mes pasado con una aplicación generada por Lovable que ya estaba en vivo en producción con clientes pagadores. Querían que agregáramos algunas funciones y "limpiáramos un poco las cosas". Lo que encontramos durante nuestra auditoría inicial de codebase fue... revelador. Claves API expuestas en código del lado del cliente. Políticas de Row Level Security faltantes en tablas que contienen datos de usuarios. Llamadas directas a Supabase sin validación del lado del servidor. Y esto no fue un caso aislado -- ahora hemos auditado seis proyectos diferentes de Lovable, y los patrones son notablemente consistentes.
Permíteme ser claro: Lovable es una herramienta impresionante para prototipado. La velocidad a la que genera UI funcional a partir de prompts en lenguaje natural es genuinamente notable. Pero hay una brecha masiva entre "prototipo funcional" y "aplicación lista para producción", y esa brecha está llena de vulnerabilidades de seguridad que la mayoría de fundadores no técnicos ni siquiera saben buscar.
Este artículo es un desglose técnico de lo que hemos encontrado en múltiples auditorías de codebase de Lovable. Si has construido algo con Lovable y estás tomando dinero o datos reales de usuarios, necesitas leer esto.
Tabla de Contenidos
- Lo que Lovable Realmente Genera
- El Problema de la Clave API
- Row Level Security: El Asesino Silencioso
- Brechas en Autenticación y Autorización
- Exposición de Lógica de Negocio del Lado del Cliente
- Funciones Edge de Supabase: Qué Está Faltando
- Patrones de Vulnerabilidad Comunes que Encontramos
- Cómo Auditar Tu Propio Proyecto de Lovable
- Cuándo Reconstruir vs. Cuándo Remediar
- Preguntas Frecuentes

Lo que Lovable Realmente Genera
Lovable genera aplicaciones React (típicamente usando Vite) con Tailwind CSS y componentes shadcn/ui, conectadas a un backend de Supabase. El stack en sí es sólido -- construimos con estas mismas herramientas regularmente en nuestro trabajo de desarrollo Next.js. El problema no son las decisiones tecnológicas. Es cómo se conectan entre sí.
Aquí está una estructura típica de proyecto de Lovable:
src/
├── components/
│ ├── ui/ # componentes shadcn
│ ├── Dashboard.tsx
│ ├── Settings.tsx
│ └── ...
├── integrations/
│ └── supabase/
│ ├── client.ts # ← Aquí es donde comienzan los problemas
│ └── types.ts
├── pages/
├── hooks/
└── lib/
El código generado es limpio y legible. Debo darle crédito a Lovable por eso. Pero la legibilidad no equivale a seguridad. La arquitectura toma decisiones que están bien para una demostración pero son peligrosas para producción.
Seamos específicos.
El Problema de la Clave API
Cada proyecto de Lovable que hemos auditado tiene credenciales de Supabase en el código del lado del cliente. Ahora, antes de que aparezcan los defensores de Supabase: sí, la clave anon está diseñada para ser pública. La documentación de Supabase lo establece explícitamente. La clave anon está diseñada para usarse en código del lado del cliente, y la seguridad se supone que se ejecuta a través de políticas de Row Level Security.
Pero aquí es donde se pone feo.
En tres de los seis proyectos que auditamos, encontramos la clave service_role de Supabase ya sea:
- Codificada directamente en un archivo de utilidad
- Almacenada en un archivo
.envque fue comprometido en el repositorio de GitHub - Referenciada en una Función Edge de Supabase que era accesible sin autenticación
La clave service_role omite todas las políticas de RLS. Si alguien la obtiene, tiene acceso completo de lectura/escritura a toda tu base de datos. Cada tabla. Cada fila. Los datos de cada usuario.
// Patrón real que encontramos en un proyecto de Lovable (claves redactadas)
import { createClient } from '@supabase/supabase-js'
// Esto estaba en un archivo llamado lib/admin.ts
// importado y usado en un componente del lado del cliente
const supabaseAdmin = createClient(
'https://xxxxx.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // ¡clave service_role!
)
Esto no fue generado directamente por Lovable -- fue agregado por el fundador cuando necesitaba funcionalidad de administrador y le pidió a Lovable que "agregara un panel de administrador". Lovable cumplió, y ya que no tiene una noción de límites de seguridad del lado del servidor vs. del lado del cliente, puso la clave donde era conveniente.
Incluso cuando solo la clave anon está expuesta (como se pretende), el modelo de seguridad se desmorona si RLS no está configurado correctamente. Lo que nos lleva al grande.
Row Level Security: El Asesino Silencioso
Row Level Security (RLS) es el mecanismo de seguridad primario de Supabase para proteger datos a nivel de base de datos. Cuando se configura correctamente, garantiza que los usuarios solo puedan acceder a sus propios datos independientemente de qué llamadas de API se realicen desde el cliente.
Cuando auditamos los seis proyectos de Lovable, esto es lo que encontramos:
| Proyecto | Tablas Totales | Tablas con RLS Habilitado | Tablas con Políticas RLS Correctas | Datos Sensibles Expuestos |
|---|---|---|---|---|
| SaaS Dashboard | 14 | 6 | 3 | PII de usuario, datos de facturación |
| App de E-commerce | 22 | 10 | 4 | Historial de pedidos, direcciones |
| Rastreador de Salud | 11 | 4 | 2 | Registros de salud, medicamentos |
| Gestor de Proyectos | 18 | 8 | 5 | Datos de clientes, documentos |
| Plataforma de Reservas | 16 | 7 | 3 | Información de contacto, horarios |
| Herramienta CRM | 20 | 9 | 4 | Datos de clientes, notas |
Lee eso de nuevo. En la aplicación de rastreador de salud -- que almacenaba información real de medicamentos y salud -- solo 2 de 11 tablas tenían políticas RLS correctas. Alguien con la clave anon (que es pública, recuerda) podría consultar los registros de salud de cada usuario.
Las fallas de RLS más comunes que vemos:
Políticas Faltantes Completamente
Lovable a menudo crea tablas sin habilitar RLS en absoluto. En Supabase, RLS está deshabilitado por defecto en tablas nuevas, lo que significa que cualquiera con la clave anon puede leer todos los datos.
-- Lo que a menudo encontramos: RLS ni siquiera habilitado
CREATE TABLE public.user_profiles (
id UUID REFERENCES auth.users,
full_name TEXT,
email TEXT,
phone TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- No ALTER TABLE ... ENABLE ROW LEVEL SECURITY;
-- No hay políticas definidas
Políticas Demasiado Permisivas
Cuando Lovable sí agrega RLS, las políticas a menudo son demasiado amplias:
-- Política común generada por Lovable
CREATE POLICY "Los usuarios pueden ver todos los perfiles"
ON public.user_profiles
FOR SELECT
USING (true); -- Esto permite que CUALQUIER usuario autenticado lea TODOS los perfiles
La corrección debería ser:
-- Cómo debería verse
CREATE POLICY "Los usuarios pueden ver su propio perfil"
ON public.user_profiles
FOR SELECT
USING (auth.uid() = id);
Políticas DELETE y UPDATE Faltantes
Incluso cuando las políticas SELECT son correctas, las políticas INSERT/UPDATE/DELETE frecuentemente faltan o son incorrectas. Encontramos casos donde cualquier usuario autenticado podría actualizar el perfil de cualquier otro usuario.

Brechas en Autenticación y Autorización
Lovable maneja la autenticación básica razonablemente bien -- configura Supabase Auth con inicio de sesión por correo/contraseña o inicios de sesión sociales, y los flujos de login/signup generalmente funcionan. Pero la autenticación (¿quién eres?) y la autorización (¿qué puedes hacer?) son cosas diferentes.
La capa de autorización casi siempre está incompleta o no existe.
Considera una aplicación SaaS multi-tenant. Los usuarios pertenecen a organizaciones. Solo deberían ver datos de su organización. Podrían tener diferentes roles (administrador, miembro, visualizador). Lovable no genera nada de esto.
Lo que típicamente encontramos:
// Recuperación de datos generada por Lovable
const { data: projects } = await supabase
.from('projects')
.select('*')
// Sin filtro para organization_id
// Sin verificación del rol o permisos del usuario
La corrección requiere cambios tanto a nivel de base de datos (RLS) como a nivel de aplicación. Necesitas una tabla memberships que mapee usuarios a organizaciones con roles, políticas RLS que verifiquen membresía, y código de aplicación que filtre apropiadamente.
Este es el tipo de trabajo de arquitectura que es difícil de parchear después del hecho. Toca cada consulta, cada componente, cada página. Si estás construyendo un SaaS multi-tenant con Lovable, esto es lo que te morderá más duramente.
Exposición de Lógica de Negocio del Lado del Cliente
Porque Lovable genera aplicaciones React puras del lado del cliente, toda la lógica de negocio vive en el navegador. Esto significa:
- Los cálculos de precios son visibles y manipulables en las DevTools del navegador
- Los feature flags para diferentes niveles de suscripción se verifican del lado del cliente
- La lógica de validación de códigos de descuento está en el bundle de JavaScript
- La limitación de velocidad de API no existe (no hay servidor para aplicarla)
Encontramos un SaaS generado por Lovable donde la verificación del nivel de precios era completamente del lado del cliente:
// Encontrado en un componente de un proyecto de Lovable
const canAccessFeature = (feature: string) => {
const plan = user?.subscription?.plan
if (plan === 'pro') return true
if (plan === 'basic' && BASIC_FEATURES.includes(feature)) return true
return false
}
Un usuario podría simplemente modificar esta función en la consola del navegador -- o llamar directamente a la API de Supabase sin esta verificación -- y acceder a funciones pro en un plan básico. La base de datos no tenía políticas que aplicaran el acceso basado en el plan.
Este es un problema arquitectónico fundamental. La lógica de negocio necesita un componente del lado del servidor. Ya sea que sea Next.js API routes, Supabase Edge Functions, o un servicio backend separado -- algo necesita validar operaciones donde el usuario no pueda manipularlas.
Esta es exactamente la razón por la que a menudo recomendamos marcos como Next.js o Astro para aplicaciones SaaS de producción -- te dan renderizado del lado del servidor y rutas de API de forma predeterminada.
Funciones Edge de Supabase: Qué Está Faltando
Algunos proyectos de Lovable sí usan Supabase Edge Functions para ciertas operaciones -- típicamente manejo de webhooks de Stripe o envío de correos electrónicos. Pero la implementación a menudo tiene problemas:
Sin validación de entrada: Las Edge Functions aceptan y procesan cualquier JSON que se les envíe sin validar forma, tipos o restricciones.
CORS configurado para permitir todos los orígenes:
// Patrón común en Edge Functions de Lovable
const corsHeaders = {
'Access-Control-Allow-Origin': '*', // Permite que cualquier sitio web llame a esto
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
Sin verificación de autenticación: La función no verifica el token JWT, así que usuarios no autenticados pueden llamarla.
Las firmas de webhook de Stripe no se verifican: En dos proyectos, el manejador de webhook de Stripe no verificaba la firma del webhook, lo que significa que cualquiera podría enviar eventos de pago falsos al endpoint.
// Lo que encontramos -- sin verificación de firma
Deno.serve(async (req) => {
const body = await req.json()
// Procesa directamente el evento sin verificar que vino de Stripe
if (body.type === 'checkout.session.completed') {
// Actualiza la suscripción del usuario
await supabaseAdmin.from('subscriptions').update({
status: 'active',
plan: 'pro'
}).eq('user_id', body.data.object.metadata.user_id)
}
})
Esto significa que un atacante podría enviar una solicitud POST a la URL del webhook con un evento falso checkout.session.completed y actualizar a cualquier usuario a un plan pro de forma gratuita.
Patrones de Vulnerabilidad Comunes que Encontramos
Aquí está un resumen de los problemas más comunes clasificados por severidad y frecuencia:
| Vulnerabilidad | Severidad | Frecuencia (de 6) | Explotabilidad |
|---|---|---|---|
| RLS faltante en tablas sensibles | Crítica | 6/6 | Fácil -- solo consulta la tabla |
| Políticas RLS demasiado permisivas | Alta | 6/6 | Fácil con clave anon |
| Exposición de clave service role | Crítica | 3/6 | Trivial si se encuentra |
| Sin verificación de webhook de Stripe | Alta | 4/6 | Media -- necesita URL del endpoint |
| Autorización solo del lado del cliente | Alta | 6/6 | Fácil con DevTools |
| Sin validación de entrada en Edge Functions | Media | 5/6 | Media |
| CORS wildcard en Edge Functions | Media | 5/6 | Fácil |
| Datos sensibles en localStorage | Media | 4/6 | Acceso físico o XSS |
| Sin limitación de velocidad | Media | 6/6 | Trivial |
| Referencias directas inseguras a objetos | Alta | 5/6 | Fácil -- cambiar ID en URL |
Cómo Auditar Tu Propio Proyecto de Lovable
Si has construido algo con Lovable que está manejando datos de usuarios reales, aquí está cómo puedes verificar estos problemas tú mismo.
Paso 1: Verifica tu Estado de RLS en Supabase
Ve a tu dashboard de Supabase → Table Editor. Haz clic en cada tabla y verifica si RLS está habilitado. Luego ve a Authentication → Policies y revisa cada política.
O ejecuta esta consulta en el SQL Editor:
SELECT
schemaname,
tablename,
rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY tablename;
Si rowsecurity es false para cualquier tabla que contenga datos de usuarios, eso es un problema crítico.
Paso 2: Busca Claves Expuestas
En tu codebase, busca:
grep -r "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" src/
grep -r "service_role" src/
grep -r "SUPABASE_SERVICE" src/
El primer patrón coincide con el inicio de las claves JWT de Supabase. Si encuentras la clave service_role en cualquier lugar en tu directorio src/, eso es una vulnerabilidad crítica inmediata.
Paso 3: Prueba las Políticas RLS
Crea una segunda cuenta de usuario de prueba. Inicia sesión como ese usuario e intenta acceder a datos del usuario uno. Verifica la pestaña de Red del navegador -- ¿estás recibiendo datos que no deberías?
También puedes probar directamente con curl:
curl 'https://YOUR_PROJECT.supabase.co/rest/v1/user_profiles?select=*' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
Si esto devuelve todos los perfiles de usuario sin autenticación, RLS está roto.
Paso 4: Verifica las Edge Functions
Revisa cada Edge Function por:
- Verificación de JWT
- Validación de entrada
- Configuración de CORS
- Verificación de firma de webhook (para manejadores de Stripe/pagos)
Paso 5: Inspecciona el Bundle del Lado del Cliente
Ejecuta npm run build e inspecciona la salida. Busca en el JavaScript construido claves de API, lógica de negocio y datos de precios. Cualquier cosa en el bundle es visible para los usuarios.
Cuándo Reconstruir vs. Cuándo Remediar
Esta es la pregunta que enfrenta cada fundador de Lovable una vez que se da cuenta de que estos problemas existen. La respuesta depende de varios factores:
Remedia si:
- Tu aplicación tiene menos de 10 tablas
- No tienes un modelo de autorización complejo (sin multi-tenant, sin roles)
- La arquitectura central (modelo de datos, estructura de página) es sólida
- Principalmente necesitas agregar políticas RLS y mover algo de lógica del lado del servidor
Reconstruye si:
- Necesitas arquitectura multi-tenant con roles y permisos
- Tu lógica de negocio es compleja y está toda del lado del cliente
- Necesitas renderizado del lado del servidor para SEO o rendimiento
- El esquema de Supabase tiene problemas estructurales significativos
- Estás a una escala donde necesitas infraestructura adecuada
Para remediación, típicamente estás viendo agregar políticas RLS en todas las tablas, migrar lógica sensible a Edge Functions o una capa del lado del servidor, implementar validación de entrada adecuada, y agregar limitación de velocidad. Este es un proyecto de 2-4 semanas para un desarrollador experimentado dependiendo de la complejidad.
Para una reconstrucción completa, típicamente recomendamos una arquitectura headless con separación adecuada de responsabilidades. Cuesta más al principio pero te da una base que escala. Consulta nuestra página de precios para una idea de cómo se ve.
Si no estás seguro de cuál es el camino correcto, estamos felices de hacer una evaluación rápida. Contáctanos en nuestra página de contacto.
Preguntas Frecuentes
¿Es Lovable seguro de usar para aplicaciones de producción? Lovable puede generar un punto de partida sólido, pero la salida necesita un endurecimiento de seguridad significativo antes de que esté lista para producción. El código generado carece de políticas RLS adecuadas, validación del lado del servidor, y lógica de autorización. Piénsalo como andamiaje, no como el edificio terminado. Absolutamente necesitas un desarrollador que revise y asegure el código antes de que usuarios reales confíen en él con sus datos.
¿Lovable expone mis claves de API de Supabase?
La clave anon de Supabase está intencionalmente pública -- eso es por diseño, y el modelo de seguridad de Supabase lo cuenta a través de RLS. El problema es cuando Lovable (o tú, a través de prompts) coloca la clave service_role en código del lado del cliente. La clave anon siendo pública solo es segura si tus políticas RLS son a prueba de balas, lo cual en proyectos generados por Lovable, típicamente no lo son.
¿Qué es Row Level Security y por qué importa? Row Level Security (RLS) es una característica de PostgreSQL que Supabase usa para controlar qué filas puede leer, insertar, actualizar o eliminar un usuario. Sin RLS, cualquiera con tu clave anon pública puede consultar tu base de datos completa -- los datos de cada usuario, cada registro privado. Es el mecanismo de seguridad más importante en una aplicación respaldada por Supabase, y es la cosa más comúnmente mal configurada en proyectos de Lovable.
¿Puedo corregir los problemas de seguridad de Lovable yo mismo sin un desarrollador? Si entiendes SQL y la sintaxis de política RLS de Supabase, puedes agregar políticas RLS básicas tú mismo usando el dashboard de Supabase. Sin embargo, obtener las políticas correctas -- especialmente para escenarios complejos como multi-tenant, recursos compartidos, o acceso de administrador -- requiere experiencia. Una política equivocada puede bloquear a los usuarios de sus propios datos o dejar todo expuesto. Para algo más que un proyecto personal simple, obtén ojos profesionales en él.
¿Cómo verifico si la base de datos de mi aplicación Lovable es segura?
La prueba más rápida: abre las DevTools de tu navegador, ve a la pestaña de Red, y mira las llamadas de API de Supabase que realiza tu aplicación. Copia el valor del encabezado apikey. Luego usa curl o Postman para consultar tus tablas directamente usando solo esa clave sin token de autenticación. Si obtienes datos de otros usuarios -- o cualquier dato en absoluto en tablas que deberían ser privadas -- tu RLS está roto.
¿Cuáles son los riesgos de seguridad más grandes con código generado por IA en general? Los generadores de código de IA se optimizan para hacer que las cosas funcionen, no para hacerlas seguras. No tienen un modelo mental de tu panorama de amenazas. Los riesgos más grandes son: secretos expuestos, validación de entrada faltante, controles de acceso demasiado permisivos, y la ausencia de límites de seguridad del lado del servidor. Estos no son únicos de Lovable -- existen problemas similares en código de Cursor, v0, Bolt, y otras herramientas de IA. La diferencia es que Lovable genera aplicaciones completas que la gente implementa directamente en producción.
¿Debería cambiar de Supabase a un backend diferente después de usar Lovable? Supabase en sí está bien. Es una plataforma sólida con capacidades de seguridad adecuadas. El problema es cómo Lovable la configura. No necesitas abandonar Supabase -- necesitas configurar apropiadamente las políticas RLS, mover operaciones sensibles a Edge Functions, y agregar la capa de autorización que Lovable omitió. La infraestructura es buena; la configuración solo necesita trabajo.
¿Cuánto cuesta corregir problemas de seguridad en una aplicación generada por Lovable? Para una remediación sencilla -- agregar políticas RLS, asegurar Edge Functions, eliminar claves expuestas, agregar validación básica de entrada -- estás viendo aproximadamente $3,000-$8,000 dependiendo del número de tablas y complejidad de tu modelo de autorización. Una reconstrucción completa con arquitectura adecuada corre $15,000-$50,000+ dependiendo del alcance. El camino de remediación casi siempre es más rentable si tu modelo de datos central es sólido.