Durante años hemos operado bajo una suposición cómoda: si no hay exploit público, no es urgente.
Esa suposición acaba de morir. Una IA ha generado un exploit funcional de 732 bytes para una vulnerabilidad de escalada de privilegios en Linux kernel presente desde 2017.
No es ciencia ficción. Es CVE-2026-31431 (Copy Fail), y el exploit ya está publicado.
El contexto real, sin dramatismo
El fallo vive en el subsistema criptográfico del kernel, concretamente en el módulo authencesn. El efecto es directo: un usuario sin privilegios puede escribir 4 bytes fuera del buffer legítimo del kernel y, combinando eso con AF_ALG y splice(), esos bytes aterrizan en el page cache encima de cualquier binario setuid que el usuario pueda leer. El resultado es escalado a root.
Lo que lo diferencia de la mayoría de LPEs (local privilege escalations):
- No depende de race conditions. Es un fallo lógico lineal: o funciona o no funciona. Según las pruebas públicas disponibles, funciona de forma consistente.
- No requiere offsets específicos de distribución. En pruebas públicas ha funcionado sin modificación en múltiples distribuciones —Ubuntu, Amazon Linux, RHEL y SUSE entre otras—.
- Lleva presente desde 2017. Casi una década en producción, silencioso.
El vector es local, no remoto. Eso limita la superficie en algunos escenarios. Pero en cuanto tienes cualquier ejecución de código no confiable —un CI runner, un notebook compartido, un pod en Kubernetes— el vector local deja de ser una barrera.
Lo que importa no es la CVE
La vulnerabilidad es seria. Pero el titular real no es la CVE: es cómo se encontró y qué implica eso para el resto.
Xint Code, una herramienta de auditoría basada en IA, tardó aproximadamente una hora en barrer el directorio crypto/ completo del kernel. El punto de partida fue humano: un investigador identificó que splice() podía empujar páginas del page cache al subsistema criptográfico y que la procedencia de páginas en scatterlists era una clase de bug poco explorada. Desde ahí, la IA tomó el relevo.
Resultado: exploit funcional, 732 bytes de Python 3, sin dependencias externas.
732 bytes. Cabe en un comentario de código. En una variable de entorno. En un script de inicialización que nadie lee. La barrera de ocultación es prácticamente cero.
Pero lo más relevante no es el tamaño. Es lo que demuestra sobre el tiempo entre descubrimiento y weaponización.
Antes: alguien encontraba un bug → pasaban meses hasta que había un exploit funcional público → “no hay exploit conocido” era una excusa válida para no parchear urgentemente.
Ahora: ese tiempo puede ser una hora. El modelo de seguridad basado en “no hay exploit público” ha muerto.
Hay otro detalle técnico que merece atención: la escritura en el page cache nunca marca la página como dirty. Esto significa que nada llega a disco. Si el sistema se reinicia o la caché se evicta, el archivo original se recarga limpio. Una imagen forense no mostraría nada. La intrusión no deja rastro en el almacenamiento.
Qué cambia operativamente
La respuesta no es solo “parchea y ya”. O más bien: sí, parchea —el commit a664bf3d603d ya está en mainline y las distribuciones principales están distribuyendo kernels actualizados— pero el parche cierra esta puerta, no el modelo mental que la dejó abierta.
Asume que el compromiso local es posible. En cualquier entorno donde haya ejecución de código que no controlas completamente, tienes que operar como si un atacante pudiera obtener root. No es paranoia, es threat modeling correcto.
La detección por firma ya no es suficiente. El exploit tiene 732 bytes y puede presentarse de mil formas distintas. Lo que necesitas detectar no es el archivo, sino el comportamiento: uso anómalo de syscalls, acceso inesperado a módulos del kernel, escalada de privilegios sin flujo legítimo.
El hardening del kernel no es opcional. Reducir la superficie de ataque —desactivar módulos innecesarios, aplicar perfiles de syscalls— es lo que convierte un exploit funcional en un exploit que no puede ejecutarse en tu sistema.
Si no puedes parchear todavía, la mitigación inmediata es deshabilitar el módulo algif_aead:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true
En la inmensa mayoría de sistemas esto no rompe nada. AF_ALG no lo usa dm-crypt/LUKS, IPsec, kTLS, ni OpenSSL por defecto.
Antes de aplicarlo en producción, verifica: lsof | grep AF_ALG. Si el resultado está vacío, no hay impacto. Si aparece algo, identifica el proceso e investiga si tiene alternativa antes de deshabilitar el módulo. Los casos donde algif_aead es necesario son raros —software criptográfico especializado que lo use directamente— pero existen. Valida en staging si tienes dudas.
Traducción práctica al homelab
Wazuh: detectar comportamiento, no firmas
CVE-2026-31431 (Copy Fail) no deja rastro en disco, así que las reglas basadas en hash o nombre de archivo no sirven aquí. Lo que sí puede detectar Wazuh:
- Uso anómalo de ptrace: un proceso que hace ptrace sobre otro sin relación de parentesco es una señal de alerta.
- Carga inesperada de módulos del kernel: si
algif_aeadse carga en un sistema donde ya lo tienes deshabilitado, eso es un evento que quieres registrar. - Cambios en binarios setuid: aunque CVE-2026-31431 (Copy Fail) no toca el disco, otros ataques sí.
syscheckactivo sobre/bin,/usr/bin,/usr/sbincon monitorización de permisos y setuid. - Escaladas de privilegios inesperadas: si un proceso que arranca sin privilegios de repente tiene capabilities o ejecuta como root sin pasar por sudo, eso merece una alerta.
La señal que quieres detectar es una cadena, no un evento aislado. En términos de correlación:
proceso sin privilegios → abre socket
AF_ALG→ llamaptracesobre otro proceso → cambio de UID a 0
Cada paso por sí solo puede ser ruido. La secuencia completa es la alerta. Wazuh con auditd puede capturar cada eslabón; la correlación entre ellos requiere reglas compuestas o un SIEM que agrupe los eventos por PID y ventana de tiempo.
Reglas de auditoría básicas a añadir en /etc/audit/rules.d/:
# Monitorizar uso de AF_ALG
-a always,exit -F arch=b64 -S socket -F a0=38 -k af_alg_socket
# Monitorizar ptrace
-a always,exit -F arch=b64 -S ptrace -k ptrace_activity
# Cambios en binarios setuid
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F perm=6000 -k setuid_change
Kubernetes: el punto más crítico
CVE-2026-31431 (Copy Fail) es también un primitive de escape de contenedor. El page cache es compartido a nivel de host. Un pod comprometido puede comprometer el host con el mismo exploit, sin importar el namespace.
Aquí conviene ser explícito: Kubernetes no es una sandbox de seguridad frente a fallos de kernel. Es aislamiento lógico, no protección frente a Linux privilege escalation. Los namespaces separan recursos, no el acceso al kernel subyacente. Un proceso dentro de un contenedor tiene las mismas syscalls disponibles que un proceso en el host —a menos que las restrinjas explícitamente.
Eso convierte cualquier workload no confiable —pipelines de CI, scrapers, código de terceros— en un vector directo al nodo.
Checklist de hardening para los pods:
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
Y a nivel de PodSecurityAdmission, asegúrate de que el namespace tiene al menos el modo restricted:
kubectl label namespace <tu-namespace> \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest
AppArmor y seccomp no son seguros al 100% contra todos los exploits de kernel, pero elevan significativamente el coste del ataque. Un exploit que funciona contra un pod sin restricciones puede fallar contra uno con seccomp RuntimeDefault porque las syscalls necesarias están bloqueadas.
Host: lo básico que se suele saltarse
- auditd activo con reglas sobre syscalls críticas. No solo para este CVE, sino como línea base de detección en cualquier sistema Linux expuesto.
- Revisar binarios pequeños y sueltos. 732 bytes puede estar en cualquier sitio. Un script de auditoría periódico que detecte ejecutables nuevos fuera de los paths estándar es barato y eficaz.
- Política de módulos del kernel. Revisa qué módulos están cargados en tus nodos.
lsmoddebería devolver solo lo que necesitas. Todo lo que no uses es superficie.
Conclusión: el problema no es la IA
El problema no es la IA.
El problema es haber dependido de un retraso que ya no existe.
La IA aquí fue una herramienta de auditoría que hizo en una hora lo que a un humano le habría llevado semanas. Esta kernel vulnerability llevaba nueve años en producción. No la había encontrado nadie porque nadie había mirado con suficiente detalle —no porque fuera difícil.
Lo que queda:
- Parchea. Punto.
- Audita el comportamiento, no solo las firmas.
- Hardening del kernel y de los contenedores no como proyecto futuro, sino como estado por defecto.
- Asume que cualquier entorno con ejecución de código no confiable es un entorno con Linux privilege escalation potencialmente disponible.
CVE-2026-31431 — Copy Fail. Página oficial con write-up técnico completo y timeline de divulgación: copy.fail
Posts relacionados en este blog:
