Resumen
El fallo, registrado como CVE-2026-82209, está en la gestión de cookies de curl (lib/cookie.c) cuando se compila con soporte de libpsl, la biblioteca que aplica la Public Suffix List (PSL). Esa lista marca dominios como github.io, bajo los que cada subdominio pertenece a un dueño distinto, y sirve precisamente para que una cookie no pueda compartirse entre ellos.
El caso problemático es muy concreto: el propio host que responde es un sufijo público (por ejemplo, github.io) y envía un Set-Cookie cuyo atributo Domain coincide exactamente con él. Según la RFC 6265 (§5.3), en ese caso la cookie debe tratarse como host-only, es decir, solo debe volver a enviarse a ese mismo host. curl, en cambio, la almacena con alcance de dominio, así que la adjunta a cualquier host hermano bajo el mismo sufijo (attacker.github.io, por ejemplo) en una petición posterior o al seguir una redirección.
Según el reporte, el código vulnerable está al menos en curl 8.21.0 (la última versión estable en el momento del reporte) y en el árbol 8.22.0-DEV, y la lógica de parse_domain() lleva sin cambios muchas versiones. Solo afecta a compilaciones con libpsl (--with-libpsl), algo habitual en los paquetes de las distribuciones.
Dónde está el error
parse_domain() marca como tailmatch (coincidencia por sufijo) cualquier cookie con un atributo Domain explícito que no sea una IP:
if(!is_ip)
co->tailmatch = TRUE;
Después, is_public_suffix() hace esta llamada:
psl_is_cookie_domain_acceptable(psl, "github.io", "github.io")
libpsl responde "aceptable" a propósito cuando el host y el dominio son iguales, porque cuenta con que quien la llama convierta la cookie en host-only. curl nunca hace esa conversión.
Por último, al construir la cabecera Cookie de salida, Curl_cookie_getlist() llama a cookie_tailmatch("github.io", 9, "attacker.github.io"). Como attacker.github.io termina en .github.io, la función devuelve TRUE y la cookie se envía al host hermano.
Pasos de reproducción
- Compila curl en el commit
c2676bf9e639e31e44b12a2cc82cf2046231b056(o cualquier versión desde la 8.21.0) en Linux o macOS de 64 bits, con libpsl activado (--with-libpslo-DCURL_USE_LIBPSL=ON). Comprueba que la salida decurl --versionincluyelibpsl. - Levanta un servidor HTTP local en el puerto 8080 con dos rutas:
/set-domain: responde302, fija la cookie siguiente y redirige ahttp://attacker.github.io:8080/sink.
`` Set-Cookie: sid=SECRET; Domain=github.io; Path=/ ``
/sink: responde200y devuelve en el cuerpo el valor de la cabeceraCookierecibida.
- Haz que los dos nombres apunten a localhost con la opción
--resolvede curl:
`` github.io:8080:127.0.0.1 attacker.github.io:8080:127.0.0.1 ``
- Lanza la petición vulnerable siguiendo redirecciones (
-L) y con un fichero de cookies (-c /tmp/domain.jar):
`` curl -sS -L --noproxy '*' \ --resolve github.io:8080:127.0.0.1 \ --resolve attacker.github.io:8080:127.0.0.1 \ -c /tmp/domain.jar \ http://github.io:8080/set-domain ``
- El cuerpo de la respuesta contiene
sid=SECRET: la cookie ha llegado aattacker.github.io, el destino de la redirección y host hermano bajo el mismo sufijo público. - En
/tmp/domain.jar, la entrada aparece como.github.iocon el indicador de subdominios aTRUE, lo que confirma que se guardó con alcance de dominio. - Primer control negativo: repite el flujo, pero con el servidor fijando la cookie sin atributo
Domain:
`` Set-Cookie: sid=HOST_ONLY; Path=/ ``
El destino attacker.github.io recibe <none> y el fichero de cookies muestra github.io con el indicador de subdominios a FALSE (host-only). Es el comportamiento correcto.
- Segundo control negativo: emite la misma cookie
Domain=github.iodesde un host hermano (tenant.github.io) en lugar del propiogithub.io. curl la rechaza como debe: el fichero de cookies queda vacío y no se envía nada al destino de la redirección.
Impacto
Quien controle un subdominio bajo un sufijo público puede recibir las cookies que el propio sufijo haya emitido con un Domain igual a sí mismo. Conseguir ese subdominio es trivial en plataformas de alojamiento como GitHub Pages, Heroku o Netlify. Se rompe así la frontera entre dueños que libpsl debería hacer cumplir.
Tiene límites: el atacante no puede plantar la cookie. Para explotarlo hace falta que el host del sufijo público emita una cookie de ese tipo y que el cliente curl contacte después con el subdominio del atacante.
Remediación
El investigador propone que, cuando psl_is_cookie_domain_acceptable() acepte la coincidencia exacta entre el host de la petición y un dominio que es sufijo público, se desactive tailmatch para que la cookie pase a ser host-only. Los demás intentos de fijar Domain a un sufijo público se seguirían rechazando. En concreto, tras la comprobación PSL en Curl_cookie_add():
if(co->tailmatch && domain && co->domain &&
curl_strequal(co->domain, domain) &&
psl_is_public_suffix(psl, lcookie))
co->tailmatch = FALSE;
El reporte figura como resuelto, pero no detalla qué cambio aplicó finalmente el equipo de curl. Se envió el 26 de agosto de 2026 y se divulgó el 3 de septiembre de 2026.