Resumen
El investigador documentó una debilidad de disponibilidad en la API GraphQL de HackerOne. La mutación verifyAccountRecoveryPhoneNumber, encargada de verificar el número de teléfono durante el cambio del teléfono de recuperación de la cuenta, no limitaba cuántas veces podía aparecer dentro de una misma petición.
GraphQL permite usar alias para pedir la misma operación varias veces con nombres distintos en un único documento. Al no haber un tope de alias, el servidor ejecutaba cada copia de la mutación de forma secuencial y repetía por completo el trabajo de backend asociado. El resultado era un aumento lineal del tiempo de respuesta: según el reporte, cada alias adicional sumaba aproximadamente 8 segundos.
Pasos de reproducción
- Preparar una petición GraphQL con varios alias de la misma mutación
verifyAccountRecoveryPhoneNumber. En el ejemplo se incluyen tres (verify1,verify2,verify3), lo que lleva el tiempo de respuesta por encima de los 20 segundos, ya que cada alias aporta unos 8 segundos de procesamiento:
mutation VerifyAccountRecoveryPhoneNumberMutations($verification_code: String!, $otp_code: String) {
verify1: verifyAccountRecoveryPhoneNumber(input: { verification_code: $verification_code, otp_code: $otp_code }) {
__typename
me {
}
}
verify2: verifyAccountRecoveryPhoneNumber(input: { verification_code: $verification_code, otp_code: $otp_code }) {
__typename
}
verify3: verifyAccountRecoveryPhoneNumber(input: { verification_code: $verification_code, otp_code: $otp_code }) {
__typename
}
}
- Enviar la petición al endpoint GraphQL con valores de
verification_codeyotp_codeválidos o de relleno.
- Comprobar que el tiempo de respuesta crece unos 8 segundos por cada alias añadido.
Impacto
Con una sola petición que incluyera varios alias de una mutación costosa, un atacante podía obligar al servidor a ejecutar repetidamente operaciones intensivas de forma secuencial, elevando mucho el tiempo de respuesta y consumiendo recursos. Según el investigador, esto podía degradar la disponibilidad hasta el punto de que usuarios legítimos sufrieran retrasos graves o no pudieran usar el servicio. Al no necesitar un gran volumen de tráfico de red, el abuso resultaba relativamente discreto.
El reporte fue resuelto y recompensado (importe no público). El programa indicó que el caso se gestionó según sus directrices de la época; a partir de octubre de 2025 HackerOne endureció su política sobre informes de denegación de servicio (ventanas de prueba definidas, restricciones de una sola petición / usuario / IP y un marco de recompensas revisado).
Qué aprender de este caso
- Al revisar APIs GraphQL, prueba a repetir una misma operación con varios alias en un único documento: si el backend ejecuta cada alias por separado sin límite, una petición basta para multiplicar el coste. Mira especialmente mutaciones que lancen trabajo caro (verificaciones, envío de OTP, llamadas a servicios externos).
- La defensa no es validar la entrada, sino acotar la forma de la consulta: limita el número de alias u operaciones por documento, aplica análisis de coste/complejidad de la consulta y limita la profundidad antes de empezar a resolver.
- Las operaciones sensibles de recuperación de cuenta (verificación de teléfono, códigos OTP) deberían llevar además control de frecuencia por usuario y por código, de modo que repetir la misma verificación muchas veces en una sola llamada no desencadene el trabajo completo cada vez.