Resumen
La documentación de libcurl dice que la opción CURLOPT_AWS_SIGV4 se desactiva dándole el valor NULL. En la práctica, esa llamada devolvía CURLE_OK pero solo hacía la mitad del trabajo: borraba la cadena de parámetros (proveedor, región y servicio) y dejaba activado el método de autenticación. Si la aplicación reutilizaba el mismo easy handle, la siguiente petición salía igualmente con una cabecera Authorization: AWS4-HMAC-SHA256, aunque fuese a otro destino.
El fallo tiene asignado el CVE-2026-86409 y HackerOne lo clasifica como divulgación de información. Afecta desde curl 7.75.0 hasta 8.21.0, y también a las versiones previas de 8.22.0 anteriores al commit c3c70440e8, que es el que lo corrige. El investigador lo probó en el commit c2676bf9e639e31e44b12a2cc82cf2046231b056.
Dónde estaba el error
El manejador de la opción, en lib/setopt.c (líneas 2061-2072), solo contemplaba el caso de que se pasara una cadena:
case CURLOPT_AWS_SIGV4:
result = Curl_setstropt(data, STRING_AWS_SIGV4, ptr);
if(CURL_EASY_STR(data, STRING_AWS_SIGV4))
s->httpauth = CURLAUTH_AWS_SIGV4;
break;
Con ptr a NULL, Curl_setstropt vacía STRING_AWS_SIGV4, pero como no hay rama else, el bit CURLAUTH_AWS_SIGV4 sigue puesto en data->set.httpauth. La opción vecina CURLOPT_HTTPSIG, en el mismo fichero, sí lo hace bien:
if(arg)
s->httpauth = (uint32_t)CURLAUTH_HTTPSIG;
else
s->httpauth &= ~(uint32_t)CURLAUTH_HTTPSIG;
La cadena de consecuencias en la siguiente transferencia es esta:
lib/transfer.c:505copia eldata->set.httpauthobsoleto, todavía con SigV4, adata->state.authhost.want.- La lógica de autenticación de
lib/http.celige SigV4 y llama aCurl_output_aws_sigv4(). - Como la cadena de parámetros está vacía,
parse_sigv4_params()(lib/http_aws_sigv4.c:820) no da error: usa por defecto"aws:amz"y saca la región y el servicio del nombre de host de la nueva URL.
El resultado es una petición firmada con las credenciales que siguieran en CURLOPT_USERPWD, sin que la aplicación lo haya pedido.
Pasos de reproducción
- Compilar una versión afectada de curl (7.75.0 o posterior) con soporte de autenticación AWS SigV4.
- Levantar un servidor HTTP de pruebas que registre, en cada petición, la ruta y la cabecera
Authorizationcompleta. - Crear un único easy handle de libcurl y configurarle un write callback para que la respuesta no interfiera en la prueba.
- Poner credenciales de prueba con
CURLOPT_USERPWD(no hacen falta reales: el servidor solo anota la cabecera generada). - Activar SigV4 dándole a
CURLOPT_AWS_SIGV4una cadena explícita con proveedor, región y servicio. - Apuntar el handle al servidor de pruebas y hacer una primera petición.
- Comprobar que esa petición lleva
Authorization: AWS4-HMAC-SHA256con el identificador de clave y el ámbito de credencial configurados. - En el mismo handle, poner
CURLOPT_AWS_SIGV4aNULLy verificar quecurl_easy_setopt()devuelveCURLE_OK. - Cambiar la URL del handle a otra ruta u otro destino, sin tocar
CURLOPT_USERPWD. - Hacer una segunda petición con el mismo handle y revisar las cabeceras registradas.
- Resultado vulnerable: la segunda petición sigue llevando una cabecera
Authorizationde SigV4, aunque según la API documentada la opción estaba desactivada. - Para confirmar que la cadena de parámetros sí se borró, comprobar que la segunda firma usa el proveedor por defecto o deduce región y servicio del nuevo host, en lugar de los valores explícitos del paso 5.
- Como control, poner
CURLOPT_HTTPAUTHaCURLAUTH_NONEy hacer una tercera petición. - Comprobar que esta no lleva cabecera
Authorization: lo que provocaba la segunda era la selección de autenticación que se había quedado colgada. - Para validar el arreglo, repetir la secuencia con una revisión que incluya el commit
c3c70440e8(o que limpie el bitCURLAUTH_AWS_SIGV4al recibirNULL). - Verificar que la primera petición sale firmada y que las dos posteriores al reinicio con
NULLya no llevan cabecera de SigV4.
Lo esperado es que, tras poner CURLOPT_AWS_SIGV4 a NULL, ninguna petición vuelva a llevar firma SigV4 hasta que la aplicación la active de nuevo.
Impacto
Para que se dé el problema tienen que coincidir varias cosas: una aplicación que reutiliza el mismo handle, mantiene las credenciales en CURLOPT_USERPWD, confía en el reinicio con NULL que describe la documentación y después hace una petición a una URL en la que un atacante puede influir. En ese caso, el destino recibe una cabecera Authorization firmada con SigV4 que no debería haber recibido.
Esa cabecera revela el identificador de la clave de acceso y una firma ligada a esa petición concreta. Según el reporte, si el servicio y la operación son compatibles, la firma podría autorizar acciones que la aplicación no pretendía. Hay dos límites claros:
- La clave secreta no viaja en la petición.
- La firma cubre método, host, ruta, cabeceras, cuerpo y marca de tiempo, lo que limita su reutilización.
Remediación
El arreglo está en el commit c3c70440e8. La corrección que propone el reporte es añadir la rama que faltaba para quitar el bit de autenticación cuando la opción recibe NULL:
case CURLOPT_AWS_SIGV4:
result = Curl_setstropt(data, STRING_AWS_SIGV4, ptr);
if(CURL_EASY_STR(data, STRING_AWS_SIGV4))
s->httpauth = CURLAUTH_AWS_SIGV4;
else
s->httpauth &= ~CURLAUTH_AWS_SIGV4;
break;
El investigador propuso además un test de regresión: activar SigV4, reiniciar la opción a NULL, reutilizar el handle y comprobar que la siguiente petición sale sin Authorization.
El reporte se envió el 27 de agosto de 2026 y se hizo público el 14 de octubre de 2026.
Qué aprender de este caso
- En librerías con opciones que activan un modo de autenticación, revisa qué pasa al "apagarlas": si la opción guarda por separado un parámetro (aquí la cadena SigV4) y un indicador de método (el bit en
httpauth), es fácil que el reinicio limpie uno y olvide el otro. - Comparar manejadores hermanos del mismo fichero es una buena forma de encontrar este tipo de fallo:
CURLOPT_HTTPSIGtenía suelseyCURLOPT_AWS_SIGV4no. Unifque pone un flag sin elelseque lo quita es la señal a buscar. - Un valor por defecto silencioso agrava el problema: al no haber parámetros, curl usó
"aws:amz"y dedujo región y servicio del host en vez de fallar. Si falta configuración obligatoria para firmar, es más seguro no firmar o devolver error. - Si tu aplicación reutiliza handles de libcurl entre destinos distintos, no confíes en desactivar una opción concreta: restablece la autenticación de forma explícita (
CURLOPT_HTTPAUTHaCURLAUTH_NONE) o retira las credenciales antes de apuntar a una URL que no controlas.