Una race condition en una aplicación web es una vulnerabilidad que aparece cuando el resultado de una operación depende del orden y el momento exacto en que varias peticiones concurrentes acceden a un mismo recurso compartido. La aplicación asume que un flujo se ejecuta de forma secuencial y atómica, comprobando una condición y actuando sobre ella, pero bajo concurrencia real dos o más peticiones se cuelan en la ventana que separa la comprobación de la acción. El efecto es que una lógica pensada para ejecutarse una sola vez, como canjear un cupón o descontar un saldo, se ejecuta varias veces con estado inconsistente. Este artículo cubre la clase de extremo a extremo, desde el descubrimiento hasta la mitigación.
Lo esencial: una race condition web nace de un patrón comprobar-y-actuar (TOCTOU) sin atomicidad. El atacante dispara peticiones simultáneas para colarse en esa ventana y provocar double-spend de cupones, sobregiro de saldo, superación de cuotas o bypass de rate limits y MFA. La explotación fiable se logra hoy con el single-packet attack desde Burp Repeater o Turbo Intruder. La defensa correcta es mover la decisión a la base de datos con operaciones atómicas, constraints de unicidad, locking o claves de idempotencia.
Qué es una race condition en aplicaciones web
Casi cualquier flujo transaccional sigue el mismo esquema interno: leer un estado, comprobar que cumple una condición y escribir un nuevo estado. En un mundo de una sola petición a la vez ese orden es seguro. El problema es que un servidor web atiende muchas peticiones en paralelo, con varios workers, hilos o instancias tocando la misma fila de base de datos. Si dos peticiones leen el estado antes de que ninguna lo haya escrito, ambas creen que la condición se cumple y ambas ejecutan la acción.
El ejemplo canónico es el saldo. La aplicación lee balance, comprueba que es mayor o igual que el importe y descuenta. Si dos retiradas de 100 euros llegan a la vez sobre un saldo de 100, ambas leen 100, ambas validan y ambas descuentan, dejando el saldo en menos 100. La comprobación era correcta de forma aislada, pero no bajo concurrencia.
Estas vulnerabilidades pertenecen a la lógica de negocio, no a un fallo de sintaxis. No hay una comilla mal escapada ni un parámetro sin sanear. Por eso escapan a los escáneres automáticos y suelen detectarse solo con pruebas manuales que entienden el propósito de cada endpoint. En la taxonomía formal se corresponden con CWE-362 (ejecución concurrente sobre recurso compartido con sincronización incorrecta) y su caso concreto CWE-367, la race condition TOCTOU.
TOCTOU: la ventana entre comprobar y usar
TOCTOU, acrónimo de time-of-check to time-of-use, describe con precisión la raíz del problema: existe un intervalo temporal entre el instante en que la aplicación comprueba una condición y el instante en que actúa basándose en ella. Todo lo que ocurra dentro de esa ventana invalida la comprobación previa.
En sistemas locales el concepto es clásico, por ejemplo comprobar los permisos de un fichero y abrirlo después, momento que un atacante aprovecha para sustituir el fichero por un symlink. En la web la ventana es la latencia entre la lectura y la escritura del estado, medida a menudo en milisegundos o incluso microsegundos. Cuanto más ancha sea esa ventana, más fácil es la explotación. Consultas lentas, llamadas a servicios externos intercaladas entre la comprobación y la escritura, o bloqueos parciales agrandan la ventana y regalan tiempo al atacante.
La consecuencia práctica es que la seguridad no puede descansar en el orden esperado de las operaciones. Si el diseño supone que la comprobación y el uso son inseparables, pero la implementación los separa en dos consultas distintas, existe una TOCTOU explotable. Cerrar esa ventana, no estrecharla, es el objetivo de una defensa correcta.
Variantes de race conditions web
La investigación moderna, en particular el trabajo de PortSwigger sobre máquinas de estado, ha ordenado estas vulnerabilidades en varias familias operativas.
Limit overrun
Es la variante más frecuente y rentable. Un límite que el negocio quiere aplicar una sola vez se supera al dispararlo en paralelo: canjear un mismo cupón o tarjeta regalo varias veces, aplicar un descuento repetidamente, sobregirar un saldo, votar más de una vez, invitar a más usuarios de los permitidos o exceder una cuota por plan. El double-spend de cupones es el caso escuela: veinte peticiones simultáneas de canje sobre un cupón de un solo uso, y varias de ellas prosperan antes de que el sistema marque el cupón como usado.
Carreras multi-endpoint
Aquí no compiten peticiones idénticas, sino peticiones a endpoints distintos que operan sobre el mismo objeto. Un patrón típico es aplicar un pago y modificar el carrito en el mismo instante, o confirmar un pedido mientras se cambia su importe. La ventana se abre porque el objeto pasa por estados intermedios que ningún endpoint valida por completo.
Sub-estados y construcción parcial
Muchos objetos existen durante un breve lapso en un estado transitorio e inválido, por ejemplo una cuenta a medio crear o un pedido sin confirmar todavía. Golpear ese sub-estado con una segunda petición puede permitir operar sobre un objeto que no debería estar aún disponible, saltándose validaciones que solo se aplican al final del flujo.
Impacto real
El impacto no es teórico. En comercio electrónico, el limit overrun se traduce en pérdida económica directa por cupones y tarjetas regalo canjeados varias veces o por saldos negativos. En banca y fintech, un sobregiro concurrente vacía la lógica de disponibilidad de fondos. En plataformas de suscripción, las cuotas por usuario, proyecto o llamada a API se superan, degradando el modelo de negocio.
Hay un vector de seguridad además del económico. Los mecanismos anti-fuerza bruta suelen implementarse como un contador que se lee, comprueba e incrementa, es decir, otro patrón TOCTOU. Enviando muchos intentos de forma simultánea, un atacante prueba más candidatos de los que el rate limit debería permitir antes de que el contador se actualice. Lo mismo aplica a códigos OTP y segundos factores: una race condition puede convertir un límite de cinco intentos en varias decenas efectivas, degradando la protección de MFA. Este cruce con autenticación conecta con lo que revisamos en el pentesting de aplicaciones web.
Cómo se explotan: Burp Repeater y Turbo Intruder
Explotar una race condition consiste en lograr que varias peticiones lleguen al servidor tan cerca en el tiempo que todas encuentren el mismo estado inicial. El gran obstáculo histórico ha sido el jitter de red: aunque envíes las peticiones a la vez, viajan por rutas y colas distintas y llegan escalonadas, cerrando la ventana antes de tiempo.
La aproximación clásica con Burp Suite es agrupar peticiones en Repeater y enviarlas en paralelo. En Burp basta con seleccionar varias pestañas, crear un grupo y elegir la opción de enviar el grupo en paralelo. Para ajustar volumen y temporización se recurre a Turbo Intruder, la extensión de scripting de alto rendimiento, con su técnica de gate: se encolan todas las peticiones reteniendo el último byte y, cuando están todas listas, se abre la compuerta con openGate para liberarlas juntas. Quien quiera profundizar en la herramienta puede empezar por qué es Burp Suite en pentesting web.
El single-packet attack
La técnica que ha cambiado el juego es el single-packet attack, presentado por James Kettle en Black Hat USA 2023. La idea es eliminar por completo el jitter de red haciendo que entre veinte y treinta peticiones lleguen al servidor dentro de un único paquete TCP. Sobre HTTP/2 esto se consigue multiplexando muchas peticiones en una sola conexión y reteniendo el frame final de cada una hasta el último momento, de modo que el servidor las recibe y las procesa prácticamente en el mismo instante. Sobre HTTP/1.1 existe una variante equivalente con sincronización del último byte sobre conexiones concurrentes.
El resultado es que la ventana de la race condition ya no compite contra la variabilidad de internet, sino solo contra el procesamiento interno del servidor, lo que hace la explotación fiable incluso a través de la red pública. Burp Repeater implementa esta técnica directamente en su opción de envío en paralelo del grupo, y Turbo Intruder incluye motores preparados para el single-packet attack. Estas mismas técnicas de concurrencia se prueban también contra APIs, un terreno que tratamos en pentesting de APIs REST y GraphQL.
Detección en auditoría
En una auditoría, el primer paso es cartografiar los endpoints con lógica de comprobar-y-actuar sobre estado compartido: canje de cupones, aplicación de descuentos, transferencias, cambios de saldo, consumo de cuotas, votaciones, contadores anti-fuerza bruta y flujos de OTP. Todo endpoint que modifique un recurso limitado es candidato.
La prueba consiste en capturar la petición relevante, duplicarla en un grupo y enviarla en paralelo con el single-packet attack, observando después si el efecto se produjo más veces de las permitidas. Un cupón que debía canjearse una vez y aparece canjeado tres, un saldo que queda negativo o un contador de intentos que no refleja todos los envíos son señales inequívocas. La metodología está recogida en la guía OWASP Web Security Testing Guide, en su prueba de race conditions dentro del bloque de lógica de negocio (WSTG-BUSL-04). Este tipo de hallazgo suele aparecer junto a otros fallos de lógica y control de acceso que documentamos en la guía completa de auditoría web.
Defensas
La regla de oro es no confiar nunca en el orden de ejecución y trasladar la decisión al único punto capaz de serializar accesos: la base de datos.
La primera defensa es la operación atómica. En lugar de leer, comprobar en la aplicación y escribir, se expresa todo en una sola sentencia condicional, por ejemplo UPDATE cuentas SET saldo = saldo - :importe WHERE id = :id AND saldo >= :importe, y se comprueba el número de filas afectadas. Si es cero, no había fondos y ninguna petición concurrente puede sobregirar, porque el motor serializa la escritura sobre la fila.
La segunda son las constraints de unicidad a nivel de base de datos. Un índice único sobre la combinación cupón mas usuario impide físicamente un segundo canje: la inserción duplicada falla aunque llegue en el mismo microsegundo. Es la barrera más robusta porque no depende del código de aplicación.
La tercera es el locking explícito. El pesimista, con SELECT ... FOR UPDATE dentro de una transacción, bloquea la fila hasta confirmar. El optimista añade una columna de versión y rechaza la escritura si la versión cambió desde la lectura. Elevar el nivel de aislamiento a serializable es otra opción, asumiendo su coste en rendimiento.
La cuarta son las claves de idempotencia, imprescindibles en pagos y mutaciones sensibles. El cliente envía un identificador único por operación y el servidor garantiza que una misma clave se procesa una sola vez, de modo que reintentos o envíos concurrentes con la misma clave no duplican el efecto. Es el patrón que popularizó Stripe y encaja de forma natural en APIs.
La quinta, para estado que no vive en una única base de datos, es el lock distribuido, por ejemplo con Redis, entendiendo sus límites y sin usarlo como sustituto de las garantías transaccionales cuando estas existen. Si necesita validar la exposición real de sus flujos transaccionales, el servicio de auditoría web y móvil de Secra prueba estos vectores de concurrencia en condiciones de ataque realistas.
Preguntas frecuentes
¿Una race condition es lo mismo que TOCTOU?
TOCTOU es la causa raíz más habitual de las race conditions web, el intervalo entre comprobar una condición y usarla, pero no toda race condition sigue exactamente ese patrón. Algunas carreras multi-endpoint explotan sub-estados transitorios sin una comprobación explícita previa. En la práctica, la mayoría de las races de lógica de negocio son TOCTOU.
¿Por qué los escáneres automáticos no encuentran estas vulnerabilidades?
Porque no son fallos de sintaxis ni de saneo de entrada, sino de lógica de negocio bajo concurrencia. Un escáner ve una petición válida que devuelve una respuesta válida. Solo enviando varias peticiones simultáneas y comprobando el efecto acumulado sobre un recurso limitado se manifiesta el problema, y eso requiere comprensión humana del propósito del endpoint.
¿Qué es el single-packet attack y por qué importa?
Es una técnica que hace que entre veinte y treinta peticiones lleguen al servidor dentro de un mismo paquete TCP, eliminando el jitter de red. Importa porque convierte races que antes solo eran explotables en laboratorio, en condiciones de red ideales, en vulnerabilidades explotables de forma fiable a través de internet.
¿Un rate limit protege frente a race conditions?
No necesariamente. Si el propio rate limit se implementa como leer-comprobar-incrementar sin atomicidad, es en sí mismo un objetivo TOCTOU: varias peticiones simultáneas pueden pasar antes de que el contador se actualice. Un rate limit robusto debe apoyarse en contadores atómicos.
¿Cuál es la mejor defensa de un vistazo?
Mover la comprobación y la acción a una única operación atómica en base de datos, respaldada por constraints de unicidad, y añadir claves de idempotencia en pagos y mutaciones críticas. Las defensas puramente en código de aplicación, sin garantía transaccional, tienden a dejar ventanas explotables.
Recursos relacionados
- Qué es SSRF: server-side request forgery
- Qué es CSRF: cross-site request forgery
- Qué es CORS y seguridad web
- Pentesting de aplicaciones web
- Qué es Burp Suite en pentesting web
- Pentesting de APIs REST y GraphQL
Auditoría de race conditions con Secra
En Secra tratamos las race conditions como vector de primer orden en la revisión de lógica de negocio, no como una curiosidad de laboratorio. Enumeramos los flujos transaccionales sensibles, reproducimos las condiciones de concurrencia con single-packet attack sobre Burp y Turbo Intruder, y verificamos si un límite de un solo uso resiste a decenas de peticiones simultáneas. Entregamos hallazgos accionables con prueba de concepto y recomendaciones de remediación centradas en atomicidad, constraints e idempotencia, priorizadas por impacto económico y de seguridad. Si necesita saber si sus cupones, saldos, cuotas o contadores anti-fuerza bruta aguantan un ataque de concurrencia real antes de que lo descubra un atacante, contacte con nuestro equipo desde esta página.
Sobre el autor
Equipo de Secra Solutions
Ethical hackers certificados OSCP, OSEP, OSWE, CRTO, CRTL y CARTE, con más de 7 años de experiencia en ciberseguridad ofensiva. Autores de los CVE-2025-40652 y CVE-2023-3512.

