El 15 de octubre de 2026 la propia autoridad de numeración de CVE del kernel de Linux publicó CVE-2026-98432, «ipv4: free inet_opt and ireq_opt after an RCU grace period», con una nota de 9,8, Crítica y el vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. A finales de mes el mismo fallo valía 8,1 para Oracle y Amazon, Importante para SUSE, Alta para Ubuntu —cuya página imprime «9.8 · Critical» dos líneas por encima de su propia prioridad— y otra vez 9,8 Crítica para Red Hat, que había estado en 8,1 hasta que cambió de opinión el 30 de octubre.
El parche son dos sentencias. El commit de Eric Dumazet, escrito el 1 de octubre y llevado a las ramas estables el 15 por Greg Kroah-Hartman, toca dos ficheros con +2 −2:
/* net/ipv4/af_inet.c — inet_sock_destruct() */
- kfree(rcu_dereference_protected(inet->inet_opt, 1));
+ kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);
/* net/ipv4/tcp_ipv4.c — tcp_v4_reqsk_destructor() */
- kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));
+ kfree_rcu(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1), rcu);
Dos sentencias, cuatro líneas modificadas. Esa distancia —entre lo pequeño que es el arreglo y lo grande que se ha vuelto la discusión sobre su gravedad— es lo que conviene entender. Si administras máquinas Linux, la nota que te han entregado no mide tu exposición: mide una métrica, elegida de forma distinta por cinco organizaciones con cinco intereses distintos.
Qué compite exactamente
tcp_v4_syn_recv_sock() se apropia de ireq->ireq_opt y se lo pasa al socket hijo como newinet->inet_opt sin copiarlo. Mientras tanto, otra CPU puede procesar un SYN retransmitido del mismo request socket y fabricar un SYNACK desde tcp_check_req(). El commit describe la consecuencia:
tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt under rcu_read_lock() only, and ip_build_and_send_pkt() and ip_options_build() then read opt->optlen twice.
Los lectores ya son correctos respecto a RCU. Los destructores no: inet_sock_destruct() libera inet_opt con un kfree() simple, y los sockets hijo de TCP no llevan SOCK_RCU_FREE. Así que el objeto puede volver al asignador mientras una segunda CPU sigue dentro de ip_options_build() leyendo opt->optlen y copiando opt->__data al SYNACK de salida.
El segundo camino es la migración de request sockets —net.ipv4.tcp_migrate_req=1, o un programa BPF_SK_REUSEPORT_SELECT_OR_MIGRATE—, donde inet_reqsk_clone() hace que el request socket antiguo y su clon compartan el mismo ireq_opt, y tcp_v4_reqsk_destructor() también usa un kfree() simple.
El disparador es una opción IP, no una opción TCP
Es el detalle que casi todos los resúmenes difuminan. El objeto obsoleto solo existe si la cabecera IPv4 del par que se conecta llevaba opciones; las notas de puntuación del CNA las nombran exactamente: «IPv4 Record Route or Timestamp bytes in a TCP SYN», guardados por ip_rcv_options() y tcp_v4_save_options().
Las opciones TCP son otra cosa: viajan en la cabecera TCP, después de los 20 bytes fijos. SYN cookies, timestamps, SACK y MSS viven ahí y no tienen nada que ver. Lo que arma el fallo es que el campo ihl de la cabecera IP sea mayor que 5. La propia mitigación de Red Hat dice lo mismo en la frase que más importa a quien escribe cortafuegos: «standard TCP options are carried in the TCP header and continue to be permitted».
Por qué el suelo es 4.4
El arreglo lleva dos etiquetas Fixes: y sus fechas explican el rango afectado:
079096f103fa— «tcp/dccp: install syn_recv requests into ehash table», 2 de octubre de 2015, de Eric Dumazet. Los request sockets empezaron a procesarse sin el lock del listener, que era justo el lock que impedía esta carrera.c905dee62232— «tcp: Migrate TCP_NEW_SYN_RECV requests at retransmitting SYN+ACKs», 12 de junio de 2021, de Kuniyuki Iwashima. Es la variante de migración.
El fallo llevaba once años latente en el primer camino y cinco en el segundo, y el rango legible por máquina del CNA dice «afectado desde 4.4»: por eso Ubuntu 14.04, con kernel 3.13, figura como «Not affected» en el rastreador. Ese dato es también la corrección a la frase más repetida de esta divulgación; volvemos a ella más abajo.
Cinco proveedores, cuatro notas
Cada cifra sale del registro del propio proveedor. Solo se mueve una métrica.
| Fuente | Calificación | Base CVSS 3.1 | Complejidad de ataque | Otros | Notas del registro |
|---|---|---|---|---|---|
| CNA del kernel (cve.org) | Crítica | 9,8 | Baja | — | Sin CWE; publicada el 15 oct 12:08 Z |
| Red Hat | Crítica | 9,8 | Baja | — | Subida desde 8,1 el 30 oct; cvss3.status: draft; CWE-825 |
| SUSE | Importante | 8,1 (SUSE) / 9,8 (columnas CNA) | Alta | CVSS 4.0 9,2 AT:P | Estado «Pending»; tres columnas v3 en paralelo |
| Oracle Linux | Importante | 8,1 | Alta | — | «preliminary and subject to review» |
| Amazon Linux | Importante | 8,1 | Alta | — | «primarily results in a system crash… or potential memory corruption» |
| Ubuntu | Alta | 9,8 | Baja | CVSS 4.0 8,3 VC:L/VI:L/VA:H | Prioridad Alta y «9.8 · Critical» en la misma página |
| NVD | — | — | — | — | Estado «Received», sin análisis propio |
Con los vectores uno al lado del otro, la discusión se reduce a un campo:
CNA / Red Hat / Ubuntu CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H 9.8
SUSE / Oracle / Amazon CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H 8.1
^^^^
El resto es idéntico: alcanzable por red, sin privilegios, sin interacción, mismo alcance y alto impacto en confidencialidad, integridad y disponibilidad. Toda la diferencia de 1,7 puntos es AC:L frente a AC:H.
No es un accidente de cálculo. Es un desacuerdo real sobre qué es una condición de carrera, y el CNA escribió su razonamiento en el registro en lugar de dejarlo implícito:
AC:L - On an accepting server, the peer can repeatedly create an option-bearing request and race a retransmitted SYN against completing and tearing down that same TCP connection. Both racing sides are attacker-induced; multicore scheduling and heap grooming do not constitute conditions outside the attacker’s influence.
Oracle y Amazon fueron en la dirección contraria, y CVSS 4.0 tiene una métrica que hace explícita su postura. El registro de SUSE conserva las dos: 9,8 con el esquema v3 y 9,2 con AT:P — Attack Requirements Present. CVSS 4.0 separó la antigua «complejidad de ataque» en dos cosas: AC (el trabajo del atacante) y AT (condiciones fuera de su control). Quien puntúa AC:H está diciendo, en efecto, que la carrera necesita suerte. CVSS 4.0 le permite decirlo sin inflar además todas las métricas de impacto.
La entrada v4 de Ubuntu va más lejos: VC:L/VI:L/VA:H, impacto bajo en confidencialidad e integridad y alto en disponibilidad. Es una lectura defendible de la versión de salón del fallo (tumba la máquina) y difícil de casar con la descripción publicada por Anthropic de un shell como root. Lo cual lleva a lo que decide la discusión para todos: el exploit existe, y nadie fuera de Anthropic lo tiene.
El relato de Anthropic es concreto en el tiempo:
In our proof of concept, it takes 48 minutes to leak a kernel pointer and another five minutes to reach the shell command execution.
53 minutos por cadena de intentos, contra un objetivo que, según ellos, necesita «a multipath TCP listener». La propiedad que Anthropic señala es la que empuja hacia AC:L: «a lost race only fails the handshake without crashing the whole system, so a determined attacker can retry indefinitely until they succeed». Quien defiende una red lee 53 minutos y ve una campaña. Una calculadora CVSS lee «reintentar para siempre, sin caídas» y ve AC:L. Ambas lecturas son correctas porque miden cosas distintas. Si tu modelo de amenaza es el escaneo oportunista, 53 minutos por máquina es caro. Si es un actor que te ha elegido, el reloj da igual — y la discusión 9,8 contra 8,1 también.
Estado del parche, comprobado el 1 de noviembre
Aguas arriba está hecho: 7.2.10 y 6.18.56 el 11 de octubre; 6.12.113, 6.6.159, 6.1.190, 5.15.223 y 5.10.272 el 15 de octubre; 7.3 el 18 de octubre — ocho commits estables, ocho líneas de mantenimiento.
Los kernels de distribución llevan su propia numeración, así que la etiqueta de upstream no dice nada de tu máquina. Esto es lo que decían los rastreadores a las 00:50 UTC del 1 de noviembre de 2026, leídos directamente en cada proveedor:
| Distribución | Estado a las 00:50 UTC del 1 nov | Versión corregida |
|---|---|---|
| Ubuntu 26.10 / 26.04 / 24.04 / 22.04 | Vulnerable — trabajo en curso | 7.3.0-10.10 / 7.0.0-43.43 / 6.8.0-149.149 / 5.15.0-203.213 |
| Ubuntu 20.04 / 18.04 / 16.04 | Vulnerable | ninguna listada |
Ubuntu 14.04 (paquete linux) | No afectada | — (3.13 es anterior a 4.4) |
| RHEL 8 / 9 / 10 | Afectado, sin parche | — |
| RHEL 6 / 7 | No afectados | — |
| Debian 13 trixie | 6.12.107-1 vulnerable, 6.12.113-1 corregida en security | DSA-6568-1 |
| Debian 12 bookworm | 6.1.176-1 vulnerable, 6.1.190-1 corregida en security | DLA-4841-1 |
| Debian forky / sid | 7.2.12-1 / 7.2.14-1 corregidas | — |
| Amazon Linux 2 y 2023 | Corregido en todos los kernels (extras 5.4/5.10/5.15, 6.12, 6.18) | avisos del 24 al 30 de octubre |
| Oracle Linux UEK 7/8/9/10 | Corregido | ELSA-2026-500397/8/9, 16 oct |
| SUSE SLES 16.0, 15 SP4–SP6 LTSS | Corregido | kernel-default 6.12.0-160000.40.1 |
| SUSE 15 SP7 | En curso | — |
| AlmaLinux 8/9/10 | Kernels corregidos en testing | 4.18.0-553.180.2.el8_10, 5.14.0-687.61.2.el9_8, 6.12.0-211.69.2.el10_2 |
Dos cosas llaman la atención. Primera: las dos distribuciones con más instalaciones —Ubuntu y RHEL— son las dos que no tienen parche publicado, diecisiete días después de que salieran los backports estables. Segunda: «trabajo en curso en 6.8.0-149.149» es un número de versión, no un arreglo; se vuelve real cuando Canonical lo publique y tú reinicies.
Rebuscando en el hilo que siguió a la divulgación, un empleado de Proxmox informó de que su kernel 7.0.14-25 incluye el arreglo y está disponible en todos sus repositorios. Es una afirmación de un comentario, no de un rastreador oficial, y no la he verificado — pero es justo el tipo de dato que falta en todos los resúmenes publicados hasta ahora.
El valor por defecto de Go que amplió el radio
El fallo está en TCP sobre IPv4, no en MPTCP. Pero el exploit funcional de Anthropic apuntaba a «Linux servers with a multipath TCP listener», y el aviso del equipo de seguridad de Go del 29 de octubre añadió la parte que convirtió una curiosidad en un problema operativo:
As of Go 1.24, Go programs enable MPTCP by default for listen sockets on Linux. This default may be changed by setting the “multipathtcp” GODEBUG: Setting “GODEBUG=multipathtcp=0” in a program’s environment will disable MPTCP by default at runtime. Placing “godebug multipathtcp=0” in the main module’s go.mod file will disable MPTCP by default at build time.
Fíjate en la granularidad de ese valor por defecto: depende de la línea go del go.mod. Un servicio compilado con una cadena de herramientas 1.24 o posterior abre listeners MPTCP sin que nadie lo haya decidido. net.ListenConfig.SetMultipathTCP anula el GODEBUG en ambos sentidos.
El mismo aviso es sincero sobre por qué eso no es una solución:
Note that disabling MPTCP on a program-by-program basis is a fragile mitigation. Accidentally leaving a single MPTCP listener exposed will still leave a system vulnerable. Further, it assumes that all viable exploits for this bug depend on MPTCP. Again, we strongly recommend upgrading to a patched kernel version.
Y sobre cambiar Go: «At this time, we believe it is premature to consider making any changes to Go (such as changing the default MPTCP behavior) in reaction to this issue.»
Lo que medimos en la máquina que escribió esto
Todas las cifras anteriores salen de una API o un rastreador. La máquina donde se escribió este artículo tiene userland Debian 13 y un kernel compilado por Ubuntu, y sirve de ejemplo de lo poco que dice una cadena de versión:
$ uname -r
6.8.0-147-generic # por debajo del 6.8.0-149.149 que Ubuntu tiene en curso
$ cat /proc/sys/net/mptcp/enabled
1 # MPTCP compilado y permitido
$ cat /proc/sys/net/ipv4/tcp_migrate_req
0 # el camino de migración de 2021 está apagado
$ ss -Mlnp
ss: command not found # iproute2 no está instalado
Tres de las cuatro comprobaciones respondieron; la cuarta falló porque la imagen no trae iproute2. Ese fallo es la lección práctica: el comando que todo el mundo repite (ss -Mlnp lista solo sockets MPTCP, así que una salida vacía significa que no hay listener MPTCP) no se ejecuta en una imagen mínima, y una lista de verificación que dé por hecho lo contrario informará silenciosamente de que no hay nada. net.mptcp.enabled = 1 por sí solo no demuestra que exista un listener: hace falta que una aplicación lo abra.
Y el kernel en ejecución no coincide con el número que publica la distribución: el paquete instalado y el kernel que corre son objetos distintos, y una actualización no cambia nada hasta que la máquina arranca con ella.
Donde se acaba la documentación
Hay cuatro cosas que no aparecen en ningún registro primario, y las cuatro cambian lo que haces después:
Por qué MPTCP. Anthropic dice que el exploit necesita un listener de multipath TCP y no dice por qué. El registro CVE no menciona MPTCP. El aviso de Go solo añade que «the underlying bug is not specific to MPTCP. It is possible that systems with no MPTCP listeners are vulnerable to similar attacks». Todos los análisis repiten la asociación sin mecanismo, porque no hay ninguno publicado. La política de divulgación de Anthropic da 90 días a los fabricantes y 45 más antes de hablar de detalles que excedan el aviso, así que la respuesta está embargada, no ausente.
Si un listener normal es explotable. Misma frase, mismo hueco. «No específico de MPTCP» habla de dónde vive el código, no demuestra que un listener TCP corriente pueda llevarse a RCE.
La prueba de concepto. No hay ninguna pública. Una búsqueda en GitHub el 1 de noviembre devolvió 36 repositorios que mencionan el CVE —el más antiguo creado el 29 de octubre a las 14:17 Z, el más reciente el 31 a las 16:04 Z—, de los cuales ocho usan palabras como PoC, trigger u oracle en el nombre o la descripción. La cifra 36 coincide con la que reportó el análisis más leído, algo poco habitual en una fuente secundaria. El catálogo KEV de CISA, en una versión fechada el 30 de octubre, todavía no incluye este CVE entre sus 1.766 entradas. Cuatro días después de un exploit de root escrito por una IA es un plazo normal para que un fallo no esté en KEV, y tampoco es prueba de que no esté pasando nada.
La clase de debilidad. El registro del CNA no incluye CWE. Red Hat asigna CWE-825, Expired Pointer Dereference. Los escáneres que clasifican por CWE no encontrarán nada con qué casar; los que leen la gravedad de NVD verán estado «Received» y ninguna nota propia, de modo que el 9,8 del CNA queda como el único número disponible. El único número que te mostrarán casi todas las herramientas es justamente el que todos los proveedores discrepantes rechazaron.
Dos comprobaciones de la comunidad que valen más que otro resumen
Los artefactos públicos más útiles no son los avisos.
Un oráculo de marcadores. Un toolkit hace que cada intento de carrera lleve un marcador único dentro de sus opciones IP y luego observa los SYNACK: una respuesta que repita el marcador de otro intento demuestra que el kernel leyó un objeto liberado. Es una prueba de alcanzabilidad que no requiere derrotar KASLR, ni preparar el heap, ni cargar un payload: se detiene en «el UAF ocurrió, aquí está el paquete que lo prueba». Su propio README es honesto: no es un exploit de un clic, y «Stage 3 … is described in …, but not implemented: without a specific kernel build it would be fiction».
Una discrepancia sobre la ventana de carrera. El mismo repositorio que trae la sonda defiende el otro lado de la discusión con sus propias palabras: el intervalo vulnerable es «roughly the distance between the ireq_opt load and the first dereference», la liberación llega «100 µs to milliseconds later», y en un kernel normal sin PREEMPT_RT «softirqs are not scheduled at all and even a flood of hard IRQs would still finish in about 10ns». Su conclusión —«You should patch your servers, but probably not panic about it»— es una afirmación técnica refutable, no una intuición. También enumera qué le haría cambiar de opinión: PREEMPT_RT, threadirqs, máquinas virtuales sobrevendidas y steering por paquete. Si tu flota está muy sobrevendida, ese es el párrafo que hay que tomarse en serio; si es hierro dedicado con valores por defecto, es la razón por la que 53 minutos no es el número que importa.
No hemos ejecutado ninguna de las dos herramientas. No enlazamos ninguna, por la misma razón que dio el análisis anterior: un disparador sin probar en producción es la forma más rápida de convertir un fallo del kernel en una caída.
Mitigaciones provisionales y lo que deja abierto cada una
| Medida | Qué cubre | Qué deja abierto | Coste |
|---|---|---|---|
nftables, hook input (Red Hat, prioridad −310) | TCP sobre IPv4 hacia el host con opciones IP | El tráfico que el host enruta o puentea hacia contenedores; el fallo en sí | Rompe redes con etiquetas CIPSO; Red Hat: «reduces exposure … but cannot fully prevent it» |
nftables, hook prerouting (Atlas/AlmaLinux) | También el tráfico reenviado | El tráfico puenteado entre contenedores del mismo host (AlmaLinux lo advierte tal cual) | Misma salvedad sobre CIPSO |
iptables -t raw -m u32 --u32 "0>>24&0xF=6:15" | Esa clase de paquete, antes de conntrack | Requiere xt_u32; los kernels RHEL 9/10 no lo traen | Solo la vía legacy |
net.mptcp.enabled = 0 | Sockets MPTCP nuevos; Go vuelve a TCP normal | Listeners no MPTCP (el fallo real); los listeners ya abiertos, que siguen siendo MPTCP hasta reiniciar el servicio; es por netns, y cada namespace nuevo arranca con MPTCP activo | Aplicaciones que necesitan MPTCP; el equipo de Go llama a desactivarlo programa a programa una mitigación «fragile» |
GODEBUG=multipathtcp=0 | Un proceso | Todos los demás binarios de la imagen | Cambio de comportamiento silencioso |
init_on_free=1 | No el fallo; hace que una lectura obsoleta devuelva ceros y estrecha la fuga | Las escrituras fuera de límites y el secuestro de flujo de control | Exige reinicio y grep -o init_on_free=1 /proc/cmdline para comprobarlo; «commonly cited cost is roughly 1–5% on workloads heavy in memory frees»; desactivado por defecto en los kernels EL que revisó quien lo propuso |
Las reglas de filtrado son las únicas medidas que tocan el disparador en lugar de los requisitos del exploit, y por eso parecen el apaño sensato — y por eso importan sus huecos: una regla en input nunca ve un paquete puenteado entre contenedores, y ese tráfico ejecuta el mismo handshake vulnerable.
Dos correcciones a las frases que verás citadas
«Afecta a todas las versiones de Ubuntu». El rastreador de Ubuntu marca 14.04 LTS trusty como No afectada para el paquete linux, porque 3.13 está por debajo del suelo 4.4 que fija el commit de 2015. Los kernels derivados son otra cosa: linux-azure en 14.04 figura como Vulnerable, porque es un kernel 4.15. La frase correcta es «todas las versiones de Ubuntu desde 16.04», no «todas». La línea 14.04 es justo el tipo de detalle que decide si una auditoría de flota produce un falso positivo en una máquina con ESM.
«Dos líneas» frente a «cuatro líneas». El commit es +2 −2: dos sentencias sustituidas, cuatro líneas cambiadas en el diff. Ambas descripciones son ciertas y no son intercambiables — un comprobador de parches basado en grep que cuente líneas buscará el número equivocado. Cuenta sentencias, o comprueba el hash del commit.
Preguntas frecuentes
¿Está mi máquina parcheada si uname -r parece nuevo? Solo si esa compilación exacta está en la lista de versiones corregidas de tu distribución. La compilación 6.8.0 corregida de Ubuntu es 6.8.0-149.149 y aún no está publicada; una máquina con 6.8.0-147 no está parcheada por mucho que se haya actualizado hace poco.
¿Importa IPv6 aquí? El primer problema no afecta a IPv6: tcp_v6_syn_recv_sock() duplica las opciones. La variante de migración sí afecta a ipv6_opt, pero solo cuando hay CALIPSO, y el commit dice que eso «will be addressed in a separate patch». En las referencias que revisamos no aparece ningún CVE para ese seguimiento.
¿Necesito MPTCP para estar en riesgo? Según el equipo de Go, no: el fallo no es específico de MPTCP. ¿Lo necesito para estar en riesgo frente al exploit publicado? Sí: es el único exploit que existe y exige un listener MPTCP.
¿Está en KEV de CISA? No, según la versión del catálogo fechada el 30 de octubre de 2026 (1.766 entradas). No estar en KEV significa que no hay explotación confirmada en campo, no que explotarlo sea impráctico.
¿Aplico la regla de nftables? Si no puedes parchear esta semana y sirves TCP sobre IPv4 desde internet, la regla cuesta poco y cierra el único disparador documentado. Ponla en el borde si puedes: todas las máquinas de detrás la heredan, incluidas las que no alcanzas. No la confundas con un arreglo, y no la apliques a ciegas si tienes redes con etiquetas CIPSO.
¿Y los contenedores? Un contenedor ejecuta el kernel del host. Una imagen nueva no cambia nada. Comprueba en el host, no dentro del contenedor — y recuerda que una regla en prerouting protege el tráfico reenviado, mientras que un paquete puenteado nunca sale del bridge del host.
La versión corta
El kernel tuvo durante once años un fallo de dos sentencias: un objeto entregado a un socket hijo sin copia y luego liberado con kfree() mientras otra CPU lo leía todavía bajo RCU. El arreglo es kfree_rcu() en dos destructores, y ya está en ocho ramas estables.
Todo lo demás es un desacuerdo sobre AC. El CNA sostiene que el atacante controla los dos lados de la carrera y puede reintentar sin límite, luego AC:L. Tres proveedores sostienen que una carrera es una carrera, luego AC:H, y CVSS 4.0 les da AT:P para decirlo con precisión. Ubuntu publica 9,8 y lo prioriza Alta. Todos describen el mismo commit de dos sentencias, y ninguno puede decirte si tu kernel lo lleva.
Esa última parte es la única que puedes resolver tú, y son cuatro comandos — tres si tu imagen trae iproute2.