USD 12.300 en cuatro días por no validar un webhook
Postmortem real: tres semanas en producción con Lovable + Supabase + Stripe. Un endpoint que aceptaba cualquier POST drenó la caja en 96 horas.
Daniel Alvarez
5 min lectura
"Veo cargos en Stripe que no coinciden con las suscripciones en mi base de datos. Creo que estoy perdiendo plata."
El mensaje me llegó un viernes a la tarde. El founder llevaba exactamente 3 semanas en producción con un SaaS B2B construido con Lovable, Supabase y Stripe. Tenía 47 usuarios pagos genuinos, tracción real, y un agujero lógico en su arquitectura que le estaba drenando la caja a un ritmo insostenible.
El diagnóstico de una suscripción fantasma
Cuando entrás a analizar un sistema en crisis, lo primero no es leer código a ciegas; es aislar el comportamiento anómalo. El síntoma era claro y doloroso: había usuarios consumiendo el tier más alto del SaaS en producción sin que existiera un pago real asociado en el dashboard de Stripe. La base de datos de Supabase decía "Premium", pero la cuenta bancaria decía cero.
El código del backend era el típico boilerplate generado por IA. Tenían un endpoint en /api/webhook esperando recibir los eventos asíncronos de la pasarela de pagos. La lógica parecía impecable a simple vista: cuando un usuario pasaba la tarjeta, Stripe mandaba un POST con el evento customer.subscription.created, y la base de datos de Supabase actualizaba el perfil del usuario, habilitando las funcionalidades premium.
El problema es que el código aceptaba cualquier POST que respetara esa estructura JSON. No validaba de dónde venía el request.
Cualquiera que supiera (o adivinara) la URL del webhook podía abrir una terminal, armar un cURL falsificando el payload de Stripe y mandarlo directo al servidor. Tu app lo recibía, leía "suscripción creada" y le abría las puertas del sistema a un usuario que jamás había puesto una tarjeta de crédito.
Y alguien lo hizo. Automatizadamente.
El impacto financiero del código sin criterio
En sistemas en producción, los bugs lógicos son muchísimo más caros que los errores de sintaxis. Un error de sintaxis rompe el build y no sale a la calle. Un error lógico sale a la calle, funciona perfecto y te funde en silencio.
En este caso, el atacante no estaba interesado en el SaaS del founder per se. Estaba interesado en que el SaaS consumía inteligencia artificial. Usaron la vulnerabilidad del webhook para automatizar la creación de cuentas premium y usar la plataforma como un proxy gratuito para gastar tokens de OpenAI sin límite.
En cuatro días, el daño acumulado fue quirúrgico y destructivo:
- 31 cuentas truchas operando a máxima capacidad en el plan más caro.
- 16 usuarios reales que se quejaron porque el sistema empezó a dar timeouts por la carga de procesamiento anómala. A esos 16 hubo que darles descuentos y explicaciones por la confusión.
- USD 2.847 quemados exclusivamente en facturas de la API de OpenAI, consumidos por las cuentas falsas.
El total del fraude directo: USD 12.300 perdidos en apenas 96 horas. Un modelo de negocio que parecía sólido y rentable en la hoja de cálculo, de repente estaba financiando la operación de un tercero porque un endpoint confiaba demasiado.
Cuatro líneas de código por diecisiete mil dólares
El arreglo técnico de esta vulnerabilidad no requiere una reingeniería de la arquitectura, ni migrar de base de datos, ni cambiar de framework. Requiere implementar criptografía básica que Stripe te enseña el día uno en su documentación oficial: validar la firma criptográfica del webhook.
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(body, sig, endpointSecret);
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
Ese es el código que faltaba. Cuatro líneas lógicas que verifican que el payload realmente fue firmado por la llave secreta de Stripe que solo tu servidor conoce.
¿El costo total del incidente? A los USD 12.300 de fraude directo, hubo que sumarle el costo de contingencia. Frenar el sangrado un viernes a la noche, bajar el endpoint temporalmente, revocar todos los tokens en Supabase, hacer un cruce manual de datos entre el dashboard de Stripe y las tablas de usuarios para purgar a los 31 atacantes sin tocar a los 47 legítimos, e implementar la seguridad correcta.
Fueron dos semanas de mi tiempo para estabilizar el sistema y hacer el handoff documentado. Eso sumó USD 4.500 más. Un total de USD 17.000 para arreglar cuatro líneas de código.
Acá es donde el founder, todavía procesando el número, me dijo la frase que escucho todas las semanas: "Pero le pedí a la IA que me armara la integración con Stripe completa, asumí que lo hacía bien".
Este es el anti-claim que nadie te va a decir cuando te venden el sueño del SaaS en un fin de semana. Lovable no escribe esta validación por default. Cursor tampoco. Bolt menos. Las herramientas de generación de código están optimizadas algorítmicamente para que veas la pantalla de éxito funcional lo más rápido posible. Escriben el "happy path" (el camino feliz). Asumen que el mundo es un lugar ordenado donde todos los POST requests vienen exactamente de donde dicen venir. No tienen un modelo de amenazas por defecto.
Casi cuarenta años de oficio frente a un prompt
Empecé a programar a los 15 años con una PC 386 y Turbo Pascal. Hoy tengo 52. Son casi 40 años de oficio peleando con sistemas. Escribía código mucho antes de que existiera Stack Overflow, y por supuesto, décadas antes de que un modelo te escupiera un módulo entero de autenticación en tres segundos.
Cambian los nombres de los frameworks, cambian las herramientas, pero la naturaleza de los sistemas en producción sigue siendo exactamente la misma. La calle no perdona.
La IA hoy te permite escribir mil líneas de código funcional en una tarde. Eso es brutal. Te ahorra la fricción inútil de la sintaxis. Pero la IA no te da el criterio para saber qué pasa cuando ese código toca pasarelas de pago reales, enfrenta asincronismo y se expone a internet abierto.
Generar una función es fácil; entender las implicancias de seguridad de no validar un request es oficio. La herramienta te da la velocidad, pero la responsabilidad técnica de lo que ponés en producción es exclusivamente tuya.
El vibe coding sirve para armar la maqueta, convencer a los primeros usuarios y validar que hay un mercado. Pero cuando empezás a cobrar, cuando hay tarjetas de crédito reales involucradas y facturas de infraestructura corriendo por detrás, la maqueta de cartón se rompe. No confíes ciegamente en un webhook que no podrías escribir a mano, ni en un código de pagos que no auditaste. En la ingeniería de software real, la velocidad sin criterio siempre termina pasándote la factura.
¿Necesitás llevarlo a producción de verdad?
Auth real, RLS, Stripe seguro, backups testeados, observabilidad, CI/CD. Yo escribo el código junto con vos o tu equipo en 1-2 semanas. Garantía 30 días.
- Duración
- 1-2 semanas
- Precio
- Desde USD 3.500

Sobre el autor
Daniel Alvarez
CTO y cofundador de FirmaLaboral.net (SaaS HRTech con 400+ PyMEs en AR + UY). 30+ años escribiendo código, hoy ayudando founders a llevar su SaaS post-vibe-coding a producción real.
¿Te avisaré del próximo?
Publico 1-2 notas técnicas por mes
Pensadas para founders que están construyendo SaaS con IA y necesitan que llegue a producción sin romperse. Sin spam, sin promos, sin newsletter genérica. Tres formas de seguirlo:
Seguir leyendo
8 min
Migrar la DB en vivo: 5 etapas, cero downtime
Dual write, backfill, shadow reads, switchover, decommission. 5 etapas para migrar una DB en producción sin apagar el sistema.
7 min
5 AM en un yacimiento: offline-first en serio
5 AM en un yacimiento patagónico. Sin internet, con guantes, frío. SaaS B2B real, no MVP de fibra óptica. Arquitectura offline-first.