Preámbulo

Programar basándose en vibras, intuición y mucha IA está guay, es rápido y cómodo, pero esta comodidad y velocidad tiene un precio a pagar.

En este capítulo analizo Besmeo, una plataforma de cartas digitales para hostelería. Un mercado saturado donde la seguridad debería ser prioritaria, pero como veremos, aquí brilla por su ausencia.

Besmeo

Su stack tecnológico está basado en Supabase y React, luce muy bien. Además tiene todos los añadidos de moda en el ecosistema vibecoding: Framer Motion, Radix UI, shadcn/ui y Lucide.

Nota: no soy un experto en ciberseguridad, y menos en React y Supabase, para esta auditoría he utilizado a mi becario de confianza: Gemini ayudándome a detectar patrones vulnerables.

Descubro también que lleva Google Analytics, Google Ads Conversion Tracking y Facebook Pixel sin permitir ni avisar al usuario de la existencia de esos rastreadores.

Registro

Es un “muro” disuasorio bastante fuerte. Probé con una tarjeta de prueba genérica, pero la pasarela de pagos la rechazó correctamente. Hasta aquí, la seguridad de la validación de pagos parece funcionar. Pero, ¿y si no necesitamos pagar para entrar?

Supabase

Como ya sé que usa Supabase como BaaS (Backend as a Service), las aplicaciones de este tipo exponen sus credenciales en el lado del cliente para poder funcionar. Basta con abrir las herramientas de desarrollador, ir a la pestaña Network, filtrar por supabase e inspeccionar las cabeceras de cualquier petición.

Request URL: https://weqrnestvnjeycoripkl.supabase.co/functions/v1/check-subscription
Apikey: <some_api_key>
Authorization: Bearer <some_secret_key>

Obtener la apikey pública, la authorization y la URL no es un hackeo, es cómo funciona Supabase. Sin embargo, esto nos da la llave para interactuar directamente con su base de datos saltándonos la interfaz visual de la web.

Descubriendo Supabase de nuevo

Con las credenciales en mano, intentamos listar el contenido de las tablas. Aunque no podemos hacer un “listado maestro” de tablas, podemos inferir los nombres comunes.

Efectivamente, el servidor devuelve información. Que los datos sean legibles SELECT no siempre es un fallo crítico si la información es pública, pero expone la estructura interna de la base de datos, facilitando el trabajo al atacante.

Entre las tablas, encuentro una llamada subscriptions. Todo apunta a que aquí se gestiona quién paga y quién no.

Para comprobar la robustez de las reglas de seguridad (RLS - Row Level Security), intento una operación destructiva: modificar el nombre de una categoría que no me pertenece.

El servidor devuelve un error. Bloqueado. Esto es una buena noticia: el RLS impide que edite datos de otros usuarios. Pero, ¿qué pasa con mis propios datos?

Inyección de una suscripción fantasma

Como el RLS está funcionando como es debido, vamos a centrarnos en las filas que que sí podemos modificar que son las nuestras. La tabla subscriptions vincula un usuario con un estado de pago. Si logro insertar una fila, podría engañar al sistema.

Oops, falló. Dio error 400, pero paradójicamente ese error es una buena noticia, significa que el servidor intentó procesar el INSERT, pero falló porque la columna no existe.

O en otras palabras: no ha devuelto 401 (Unauthorized) ni 403 (Forbidden), sino que los datos no encajaban con el esquema, eso insinúa que el RLS podría estar permitiendo el INSERT Así que vamos con la siguiente tarea.

Introspección OpenAPI

Veamos el esquema público para ver exactamente qué columnas tiene la tabla subscriptions. Esto es debido a que Supabase auto-genera documentación.

¡Bingo!

El ataque: un INSERT quirúrgico

Como ya tenemos el esquema de la tabla, hacemos un INSERT rellenando todas las columnas enviando lo mínimo indispensable.

Se creó la suscripción, vayamos a comprobarlo.

Como veis, se ha podido saltar toda la seguridad con unos pocos scripts y con la ayuda de Gemini.

Demostración final

Conclusión

Tenemos una cuenta Premium totalmente funcional sin haber introducido una tarjeta de crédito y sin haber pagado un solo céntimo. ¿El tiempo invertido? Apenas unos minutos de inspección y un par de consultas a la API.

Este caso de Besmeo es el ejemplo canónico de los peligros del vibecoding. La aplicación cumple perfectamente con la estética moderna: componentes pulidos, animaciones suaves y un stack tecnológico de vanguardia. La “vibra” del producto transmite profesionalidad y confianza. Sin embargo, bajo esa capa de pintura fresca, los cimientos están húmedos.

El fallo aquí no es de Supabase ni de React. El fallo es metodológico:

El desarrollador (o la IA que lo asistió) confió en que ocultar el formulario de registro tras un muro de pago en la interfaz era suficiente. Olvidó la regla de oro: nunca confíes en el cliente.

Es interesante ver cómo la IA configuró correctamente la seguridad para las categorías (bloqueando la escritura), pero dejó la puerta trasera abierta de par en par en la tabla más crítica del negocio: subscriptions. Esto es típico de los LLMs: resuelven tareas aisladas correctamente, pero a menudo pierden el contexto global de la seguridad del sistema.

Herramientas como v0 o Lovable permiten construir la “casa” en tiempo récord, pero si el “arquitecto” no revisa si las cerraduras de las puertas son reales o de cartón piedra, el resultado es una aplicación que, en términos de seguridad, es un queso gruyer.

El vibecoding democratiza la creación de software, sí, pero también democratiza la creación de deuda técnica y vulnerabilidades. Si vas a dejar que una IA escriba tu backend, asegúrate de tener los conocimientos suficientes para auditar lo que ha escrito. De lo contrario, tu modelo de negocio no será SaaS, será Open Source involuntario.