Saltar al contenido

Guía

Cómo revisar la seguridad de una app que construiste con IA

9 minutos de lectura · Publicado

El código escrito con un asistente no es peor que el escrito a mano. Se escribe más rápido, y la revisión que ocurría en los huecos — mientras leías documentación, mientras esperabas a un colega — no ocurre en absoluto. Los errores de abajo no son prueba de que la herramienta sea descuidada. Son prueba de que nadie le hizo la segunda pregunta.

Cada sección nombra un patrón, explica por qué se repite y te da algo concreto que comprobar. No hace falta ser ingeniero de seguridad para recorrerlo; hace falta una hora y la búsqueda de tu editor.

1. Autorización que nadie pidió

Es, de lejos, el hallazgo serio más habitual. Pediste un endpoint que devuelve un pedido. Recibiste uno:

export async function GET(request, { params }) {
  const order = await db.order.findUnique({ where: { id: params.id } });
  return Response.json(order);
}

Funciona. Devuelve el pedido. Nada en el código parece mal, porque nada está mal respecto a lo que pediste. Lo que falta es la comprobación de que quien hace la petición puede ver ese pedido concreto — y no lo pediste, porque cuando describes una funcionalidad describes el camino feliz.

Qué comprobar. Busca en el código cada sitio donde se busca un registro por un identificador que vino de la petición: un parámetro de ruta, una query, un campo del cuerpo. En cada uno, responde en voz alta: ¿qué impide que alguien ponga otro id? Si la respuesta es «la interfaz solo les muestra los suyos», has encontrado uno. La interfaz no es un control; cualquiera puede llamar al endpoint directamente.

Qué hacer. Pon al propietario en la consulta en lugar de comprobarlo después. Una búsqueda acotada a { id, userId: session.userId } no puede devolver la fila de otra persona, mientras que una búsqueda seguida de un if se la puede saltar el siguiente que copie el patrón y olvide la segunda mitad.

2. Secretos que acabaron en el repositorio

Un asistente escribirá gustoso const stripe = new Stripe("sk_live_…") si eso hace que el ejemplo funcione, y un archivo creado antes de configurar .gitignore se commitea la primera vez que ejecutas git add .. El segundo caso también pillará a desarrolladores experimentados.

Qué comprobar. Busca los prefijos que usan tus proveedores — sk_, rk_, AKIA, ghp_, -----BEGIN — y luego revisa el historial, no solo el árbol de trabajo: git log --all -p -S "sk_live". Una clave que borraste en un commit posterior sigue en el repositorio, y cualquiera que pueda clonarlo puede leerla.

Qué hacer. Rótala. Quitar un secreto de un repositorio no lo des-divulga, y reescribir el historial no ayuda si el repositorio fue público alguna vez o se clonó. Primero rota, después limpia.

3. Flujos de pago que confían en el navegador

Las integraciones de pago son largas, y lo que se acorta es lo que no hace falta para que una transacción de prueba funcione. Se repiten dos fallos.

El primero es un manejador de webhook que lee el cuerpo del evento sin verificar la firma. Funciona perfecto en pruebas, porque lo único que envía eventos es tu proveedor. También significa que cualquiera que conozca la URL puede decirle a tu aplicación que una factura se pagó.

El segundo es un importe que llega del cliente. Si el navegador envía { priceId, amount } y el servidor cobra amount, el precio de todo lo que vendes es un número en las herramientas de desarrollador de alguien.

Qué comprobar. Encuentra la ruta del webhook y confirma que verifica una firma antes de hacer nada con el payload — y que rechaza, en lugar de registrar y continuar, cuando la verificación falla. Luego encuentra dónde creas un cargo o una sesión de checkout y confirma que el importe sale de tu propia base de datos, claveado por un identificador de producto, nunca de la petición.

Comprueba también que un evento duplicado sea inofensivo. Los proveedores reintentan, así que un manejador que concede un mes de acceso cada vez que lo llaman acabará concediendo varios.

4. Dependencias que nadie ha mirado desde entonces

Los paquetes estaban al día el día que se instalaron. Ese día fue hace unos meses, y los avisos se publican continuamente. Esto no es un problema de IA; está en esta lista porque un proyecto construido en un fin de semana es un proyecto sin hábito de mantenimiento todavía.

Qué comprobar. Ejecuta el comando de auditoría de tu gestor de paquetes. Lee la salida, no el recuento: lo que importa es si la ruta de código vulnerable es una que tu aplicación usa de verdad, y una dependencia solo de build con un aviso grave suele ser menos urgente que una que atiende peticiones con uno medio.

Qué hacer. Actualiza y luego ejecuta tus tests. Si una actualización es una versión mayor que no puedes tomar hoy, escribe por qué y cuándo lo harás: un riesgo aceptado con fecha es una decisión, y un riesgo aceptado sin ella es algo que olvidaste.

5. Configuración que estaba bien en tu portátil

Los ajustes de desarrollo que sobreviven a producción son una categoría propia: una regla CORS permisiva añadida para que un front local funcione, un endpoint de depuración que devuelve variables de entorno, una cookie de sesión sin Secure o HttpOnly, una página de error que muestra un stack trace.

Qué comprobar. Carga tu sitio de producción y mira las cabeceras de respuesta. ¿La cookie de sesión tiene HttpOnly, Secure y un valor de SameSite? ¿Un error no controlado muestra un stack trace? Pide una ruta que creas interna, sin sesión, y mira qué vuelve. Busca en la configuración "*" en cualquier cosa relacionada con CORS y cualquier comparación contra NODE_ENV que apague una comprobación.

Un orden aproximado para trabajar

  1. Secretos en el repositorio y su historial. Rota lo que encuentres.
  2. Autorización en cada endpoint que lee o escribe un registro por id.
  3. Pagos: verificación de firma del webhook, luego importes y derechos resueltos en el servidor.
  4. Avisos de dependencias, con una decisión registrada para lo que no corrijas.
  5. Configuración de producción: cabeceras, cookies, CORS, salida de errores, rutas de depuración.

El orden es por lo grave que es el resultado si te lo saltas, no por cuánto trabajo es. Una clave de pago divulgada y un cliente leyendo los datos de otro son las dos cosas que no se deshacen con una disculpa.

Qué añade un análisis a hacer esto a mano

Recorrer la lista tú vale la hora, y encontrarás cosas. Lo que no harás de forma fiable es repetirlo: después de la tercera funcionalidad, la lista está en un documento que nadie ha abierto. La automatización merece la pena por la repetición, no por la brillantez.

Audixa ejecuta estas comprobaciones contra tu repositorio y, cuando hayas demostrado que controlas el dominio, contra la configuración que sirve tu sitio. Cada resultado trae el código que coincidió, una explicación de qué podría pasar y los pasos para corregirlo — y cuando hayas corregido algo, el siguiente análisis te dice si de verdad se ha ido. Ver qué comprueba, o leer qué ocurre durante un análisis.

Una cosa no te dirá: que tu aplicación es segura. Un análisis sin hallazgos significa que las comprobaciones que se ejecutaron no encontraron nada, y saber cuáles se ejecutaron es la diferencia entre que eso sea información útil y que sea tranquilidad.

Ejecuta las comprobaciones de esta guía de forma automática

Conecta un repositorio o un servidor, ejecuta un análisis y lee los hallazgos, cada uno con su evidencia y los pasos para corregirlo.

Crear mi cuentaVolver a las guías

Sin cambios automáticos en tu código ni en tus servidores.