Reports
MEDIA[AUTENTICACIÓN]#3923520

curl 8.21.0 en Windows reutiliza conexiones Negotiate con la identidad equivocada (CVE-2026-19931)

En Windows con SSPI/Negotiate, libcurl 8.21.0 podía reutilizar una conexión autenticada con las credenciales del usuario de sesión para una petición que pedía otras credenciales, y el servidor la atendía con la identidad anterior.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

El fallo está en la lógica con la que libcurl decide si una conexión ya abierta del pool puede aprovecharse para una petición nueva que usa autenticación Negotiate (SPNEGO). El investigador lo reprodujo en Windows con SSPI en la versión 8.21.0; con la 8.20.0 no se reproduce.

Cuando una petición se autentica con Negotiate sin credenciales explícitas, SSPI usa las del usuario de Windows que ejecuta el proceso (credenciales "ambientales"). Esas conexiones pueden quedar con conn->creds == NULL. La función url_match_auth_nego() solo compara credenciales y origen si conn->creds tiene valor, así que con esas conexiones la comprobación directamente no se hace:

if(m->want_nego_http) {
  if(conn->creds &&
     (!Curl_creds_same(conn->creds, m->data->state.creds) ||
      !Curl_peer_equal(conn->creds_origin, m->data->state.origin)))
    return FALSE;
}

El resultado es que una petición posterior que sí trae credenciales propias puede acabar enviándose por la conexión ya autenticada, y el servidor la procesa como si viniera del primer usuario. HackerOne lo clasifica como "Authentication Bypass by Primary Weakness", con identificador CVE-2026-19931 y severidad media.

El reporte se envió el 7 de agosto de 2026 y se hizo público el 3 de septiembre de 2026.

Pasos de reproducción

El investigador adjuntó dos ficheros: poc.c, un reproductor mínimo con libcurl, y server.cs, un servidor Negotiate local para Windows. El procedimiento es:

  1. Arrancar el servidor Negotiate local de Windows (server.cs).
  2. Ejecutar el PoC como un usuario de Windows A (en su prueba, Administrator).
  3. La petición A usa CURLAUTH_NEGOTIATE sin credenciales explícitas.
  4. La petición B usa otro easy handle dentro del mismo CURLM y pasa credenciales explícitas de userB.
  5. Con curl 8.21.0, la petición B reutiliza la conexión que abrió A.

Resultado observado, comparando ambas versiones:

8.20.0:
A default        -> Administrator
B explicit userB -> userB

8.21.0:
A default        -> Administrator
B explicit userB -> Administrator

Si se desactiva la reutilización de conexiones, B se autentica correctamente como userB.

Impacto

Una petición configurada para un usuario puede ejecutarse con la identidad de una conexión del pool autenticada previamente por otro. En la prueba, la petición que debía hacerse como userB llegó al servidor como Administrator.

Remediación

El investigador propuso que la comparación de credenciales y origen no dependa de que conn->creds tenga valor, sino de que la conexión haya entrado ya en el estado de autenticación Negotiate:

 if(m->want_nego_http) {
-  if(conn->creds &&
+  if((conn->http_negotiate_state != GSS_AUTHNONE) &&
      (!Curl_creds_same(conn->creds, m->data->state.creds) ||
       !Curl_peer_equal(conn->creds_origin, m->data->state.origin)))
     return FALSE;
 }

El reporte figura como resuelto y con CVE asignado, pero no detalla qué cambio concreto aplicó finalmente el proyecto curl ni en qué versión.