Revisión de seguridad para vibe coding: qué probar antes del lanzamiento

Vibe Coding Rescue · 2026-07-22 · Datos y seguridad
Última revisión 2026-07-23Incluye Next.js · Supabase · StripeFuentes oficiales 14

Un inicio de sesión exitoso y un pago de prueba exitoso pueden hacer que el lanzamiento parezca listo. Los errores de seguridad tienden a aparecer en las solicitudes que deberían fallar. Esta es una revisión práctica antes del lanzamiento, no sustituye una evaluación profesional de seguridad.

Ejecuta pruebas activas solo en sistemas de staging que sean tuyos o para los que tengas permiso explícito. Usa el modo de prueba del proveedor de pagos.

Verifica si los secretos del servidor llegaron al navegador

Abre el sitio desplegado y inspecciona Fuentes, Red y Almacenamiento en las herramientas del desarrollador del navegador. Algunos valores, como una clave pública de Supabase, están diseñados para ser públicos. sb_secret_..., service_role heredado, sk_live_... y whsec_... de Stripe, y las claves privadas nunca deben estar presentes en el navegador.

En Next.js, un valor referenciado estáticamente como process.env.NEXT_PUBLIC_NAME se inserta en el bundle del navegador durante next build. Permanece fijo si ese build se promueve posteriormente a otro entorno. Una búsqueda dinámica como process.env[varName] no se incluye automáticamente, pero eso no es una forma segura de ocultar un secreto. No asignes el prefijo NEXT_PUBLIC_ a valores exclusivos del servidor; léelos únicamente desde código del servidor.

La ausencia de un archivo .env en el directorio actual demuestra muy poco. Busca en el código fuente, los bundles generados, el historial de Git, las variables de entorno de CI/CD, las variables de entorno de la plataforma de despliegue y los registros. Este patrón es solo un punto de partida; usa un escáner de secretos dedicado y también las alertas de GitHub.


rg -l --hidden --glob '!.git/**' --glob '!node_modules/**' \
  '(sb_secret_|SUPABASE_SERVICE_ROLE_KEY|service_role|sk_(live|test)_|sk-proj-|gh[pousr]_|github_pat_|AKIA[0-9A-Z]{16}|whsec_|BEGIN ([A-Z ]+ )?PRIVATE KEY)' .

Esa orden solo verifica el checkout actual y muestra nombres de archivo en lugar de valores coincidentes. Escanea el historial completo de Git por separado con una herramienta que no imprima valores sin procesar, o usa el escaneo de secretos de GitHub. Si un secreto real se filtró, la revocación viene antes de la limpieza superficial: crea una credencial de reemplazo, migra cada consumidor, deshabilita la credencial antigua y luego aborda la historia del repositorio. Nunca pegues un secreto completo en un informe de búsqueda o en una incidencia.

Cruza el límite de autorización con dos usuarios

Crea cuentas de prueba A y B, luego compara:

Ocultar un botón no es autorización. El servidor y la base de datos deben validar la sesión, el rol y la titularidad del objeto en cada solicitud.

Con Supabase, revisa la exposición de la API de datos, los privilegios GRANT que poseen anon y authenticated, y todas las políticas RLS existentes juntas. RLS selecciona filas permitidas; no oculta columnas. Protege las direcciones de correo, las notas internas y otros campos restringidos mediante privilegios de columna, una vista segura que exponga solo los campos necesarios o una API del servidor. Las políticas existentes permisivas pueden combinarse con nuevas políticas usando OR, así que también busca reglas amplias como using (true).

Revisa CORS y CSRF por separado

CORS controla cómo un navegador puede leer una respuesta de otro origen. No es autenticación ni autorización, y no impide que las solicitudes lleguen a enviarse. Devuelve Access-Control-Allow-Origin solo para un Origin que coincida exactamente con tu lista de orígenes permitidos. Usa Access-Control-Allow-Credentials: true solo donde se requieran cookies. Si los encabezados de respuesta varían según el origen de la solicitud, envía Vary: Origin para que los cachés no mezclen respuestas para distintos orígenes.

Para solicitudes POST, PUT, PATCH y DELETE con autenticación por cookie, usa la protección CSRF del framework o un patrón probado de token CSRF, y valida Origin. Una solicitud GET solo de lectura no debe cambiar el estado. Secure, HttpOnly y una configuración adecuada de SameSite fortalecen una cookie de sesión, pero no suelen reemplazar un token CSRF.

Un endpoint invocado desde el exterior, como un webhook de Stripe, puede estar excluido de la verificación normal del token CSRF. Mantén esa excepción limitada y exige una firma válida de Stripe en la ruta.

Valida la entrada cuando la aceptas y cuando la renderizas

Almacenar la cadena literal <script> no prueba por sí misma una vulnerabilidad. Valida la longitud, el tipo, el formato y el rango en el servidor, luego codifica los valores almacenados para su contexto de salida —HTML, URL, JavaScript u otro destino.

En staging, envía caracteres especiales, valores sobredimensionados y valores en los límites. Verifica que permanezcan inofensivos en cualquier lugar donde aparezcan. También verifica que las respuestas de error no revelen SQL, rutas internas de archivos o trazas de la pila.

Prueba los pagos desde el webhook sin procesar hasta las entregas duplicadas

Un usuario puede modificar los valores de precio y cantidad enviados por el navegador. Vuelve a calcularlos en el servidor a partir de un ID de producto de confianza e impón allí las cantidades permitidas. Cambia el estado del pedido solo después de validar el webhook del proveedor de pagos, no porque el navegador mostró un mensaje de éxito.

La verificación de la firma de Stripe requiere el cuerpo de la solicitud sin procesar, antes de analizarlo o volver a serializarlo, el encabezado Stripe-Signature, y la clave de firma para ese endpoint. Confirma que un analizador JSON global no altere el cuerpo antes de que la ruta de webhook lo reciba.

Devuelve un 2xx rápidamente después del mínimo trabajo sincrónico, como la verificación de la firma y la inserción en la cola, y pasa después el trabajo lento a una tarea asíncrona. Los webhooks pueden entregarse más de una vez. Registra los valores event.id procesados; ya que eventos separados aún pueden referirse al mismo objeto, también inspecciona event.type y data.object.id. Usa restricciones de unicidad y transacciones en la base de datos para que una actualización de pedido o pago tenga un efecto único incluso si se ejecuta nuevamente. Si tu servidor reintenta una solicitud POST de la API de Stripe, reutiliza la misma clave de idempotencia para la misma operación.

En modo de prueba, prueba un importe modificado, una firma inválida, el reenvío del mismo evento, entrega fuera de orden y un reintento después de que el procesamiento posterior falle.

Limita acciones sensibles y almacena contraseñas deliberadamente

Registro, inicio de sesión, restablecimiento de contraseñas, códigos de verificación y API de pago necesitan límites de solicitudes. Un límite solo por IP no gestiona bien ni las redes compartidas ni ataques distribuidos. Diseña límites por cuenta, IP y operación, luego verifica la respuesta 429 y el mensaje mostrado al usuario.

Si debes almacenar contraseñas tú mismo, la primera opción de OWASP es Argon2id. Considera scrypt si Argon2id no está disponible; reserva bcrypt para compatibilidad con sistemas legados. Las contraseñas en texto plano, el cifrado reversible y los hashes rápidos de propósito general no son apropiados. La autenticación gestionada aún deja la autorización de la aplicación, la expiración de la sesión y la configuración de redirección de inicio de sesión que todavía debes revisar.

Conserva señales útiles para investigar, no secretos, en los registros

Busca en las consolas del navegador y en los registros del servidor encabezados Authorization y Cookie, tokens de acceso y de refresco, IDs de sesión, contraseñas, cadenas de conexión a la base de datos, claves privadas y datos de tarjetas de pago. No registres esos valores. Enmascara o aplica un hash a los identificadores donde se requiera una referencia estable. Para datos personales como direcciones de correo, define la necesidad operativa, el período de retención y el control de acceso, y mantén solo lo necesario.

Registra, en cambio, los fallos de autenticación, denegaciones de autorización, cambios de clave o permisos, y transiciones de estado de pago de forma consistente. La hora, el resultado y un ID interno del usuario o solicitud pueden proporcionar un registro de auditoría sin exponer una credencial. Revisa quién puede leer los registros y cuánto tiempo se conservan.

Repite las mismas solicitudes fallidas después de la corrección

Un secreto filtrado debe revocarse inmediatamente. Los cambios que deben desplegarse juntos—RLS, GRANT, y el código de la aplicación, por ejemplo—requieren un despliegue más controlado. Valida el conjunto en staging, documenta una secuencia de despliegue breve y prepara una ruta de rollback.

Después del despliegue, vuelve a ejecutar el caso sin iniciar sesión, las cuentas A y B, las verificaciones CSRF y los flujos de pago exitosos, fallidos y duplicados. Pasar esta lista no prueba que el producto no tenga vulnerabilidades. Si un servicio público maneja datos personales o pagos, contrata una revisión independiente con un alcance definido.