Volver

2026/11/10

Kyverno CVE-2026-124440: cuando el motor de políticas se convierte en el atajo hacia cluster admin

En Kyverno 1.19.1, un tenant que puede crear políticas en un namespace puede llegar a cluster admin. Cómo funciona el bypass y qué revisar antes de actualizar.

Muchos equipos usan Kyverno para mantener aislados a los tenants de Kubernetes. Kyverno comprueba cada objeto frente a las políticas antes de que el API server lo almacene y puede permitir que los responsables de cada namespace escriban sus propias políticas para su namespace. CVE-2026-124440, publicada el 8 de noviembre de 2026, muestra cómo puede fallar esa delegación. En Kyverno 1.19.1, un tenant que solo puede crear políticas en su propio namespace puede hacer que Kyverno actúe fuera de ese namespace y, paso a paso, llegar a cluster admin.

La corrección está disponible desde el 20 de octubre en Kyverno 1.19.2. Los clústeres que no instalaron esa versión siguen expuestos. Este artículo explica qué falló, cómo funciona la escalada y qué revisar en sus propios clústeres.

Puntos clave

  • CVE-2026-124440 (advisory de GitHub GHSA-39w8-hv5g-f73w) afecta a Kyverno 1.19.1 y está corregida en 1.19.2. El registro CVE le asigna 9.4 según CVSS 4.0 y 9.9 según CVSS 3.1.
  • El atacante solo necesita permiso para crear una Kyverno Policy de ámbito de namespace en su propio namespace.
  • El apiCall de la política se ejecuta con la ServiceAccount del admission controller de Kyverno, que puede leer otros namespaces y crear admission webhooks para todo el clúster. Ese camino conduce a cluster admin.
  • El advisory no indica ninguna solución provisional. Actualice a 1.19.2 y después revise quién puede crear políticas y qué webhooks existen.
  • En las fuentes que hemos revisado no se ha informado de explotación real.

Qué debía hacer el namespace clamp

Las políticas de Kyverno pueden obtener datos de la API de Kubernetes mientras evalúan una solicitud. Esta función se llama apiCall: una regla indica un urlPath, Kyverno llama al API server y el resultado se usa en la regla. La llamada se hace con la propia ServiceAccount de Kyverno, no con los permisos de quien escribió la política.

En las ClusterPolicies, que se aplican a todo el clúster y las escriben los administradores de la plataforma, esto es lo esperado. En las Policies de ámbito de namespace, que se puede permitir escribir a los tenants, es un riesgo. Advisories anteriores (GHSA-c5qq-7g2q-cpqp y GHSA-5qq8-67g6-4h2w) mostraron que una Policy de ámbito de namespace podía usar apiCall para leer otros namespaces o escribir objetos de ámbito de clúster. Kyverno 1.19.1, publicada el 10 de septiembre de 2026, añadió un «namespace clamp»: antes de ejecutar la llamada, Kyverno comprueba que la ruta no salga del namespace de la propia política.

Dónde divergen la comprobación y la acción

El clamp de 1.19.1 no comprobaba la cadena que realmente enviaba. Según el advisory, decodificaba el percent-encoding de urlPath, normalizaba el resultado (de modo que se resolvieran los segmentos ..) y comprobaba el namespace en esa copia depurada. La solicitud en sí se enviaba después con la ruta original, sin procesar.

Esto funciona mientras la decodificación tenga éxito. Pero si la ruta contiene un percent-escape mal formado, como un % suelto en una query string al final, la decodificación falla. En ese caso, el código de 1.19.1 pasaba a comprobar la cadena sin procesar, todavía codificada. El API server no tiene ese mecanismo alternativo: decodifica la ruta por completo y enruta la solicitud. Así, el clamp ve el namespace del propio tenant, mientras que el API server ve segmentos .. codificados que salen de él, hacia otro namespace o hacia una colección de ámbito de clúster.

El advisory subraya que se trata de una clase de entradas, no de un único payload. Bloquear una cadena literal concreta no cerraría el problema. La corrección duradera consiste en validar y ejecutar exactamente la misma ruta.

Eso es lo que hace 1.19.2. Según nuestra lectura del código fuente de 1.19.2, Kyverno construye ahora una única forma canónica de la ruta, rechaza las rutas que no puede canonicalizar, comprueba el namespace sobre esa forma y envía esa misma forma al API server. Un problema hermano corregido en la misma versión, CVE-2026-122310 (GHSA-3xfv-vq8x-qhg4), aprovechaba la misma separación entre la comprobación sobre la copia depurada y la solicitud sin procesar, ocultando segmentos ../ detrás de # o ?. Es una CVE independiente, con su propio registro.

La cadena de escalada, paso a paso

Quien informó del fallo demostró la cadena en Kubernetes 1.31 con Kyverno 1.19.1 instalado desde el chart de Helm estándar con los valores por defecto.

  1. Crear una Policy de ámbito de namespace. El único privilegio del tenant es crear policies.kyverno.io en su propio namespace. La política contiene un apiCall cuya ruta supera el clamp pero se enruta a otro lugar.
  2. Activarla. Crear cualquier objeto corriente que coincida con la política, como un ConfigMap en el namespace del tenant, hace que Kyverno evalúe la regla y ejecute la llamada con la ServiceAccount de su admission controller.
  3. Leer en otros namespaces. La misma técnica permite leer objetos de otros namespaces, incluidos Secrets si el deployment de Kyverno tiene permiso para leerlos.
  4. Crear un webhook para todo el clúster. La ServiceAccount puede crear MutatingWebhookConfigurations y ValidatingWebhookConfigurations, por lo que el tenant puede registrar su propio webhook, que a partir de entonces intercepta y reescribe las solicitudes de admisión en todos los namespaces.
  5. Llegar a cluster admin. El advisory describe cómo usar ese webhook para modificar pods creados en kube-system y, desde ahí, conceder al tenant permisos de cluster-admin. El resultado es la pérdida total de confidencialidad, integridad y disponibilidad.

No se necesita ninguna interacción del usuario, y el webhook se activa con la actividad normal del clúster.

A quién afecta

El registro CVE indica que Kyverno 1.19.1 está afectada y que 1.19.2 no lo está. Las versiones anteriores a 1.19.1 no tienen este bypass concreto, porque ni siquiera tienen el clamp. Sí están afectadas por los advisories anteriores que el clamp pretendía corregir, así que quedarse en una versión más antigua no es una alternativa segura. El riesgo es mayor donde los responsables de namespaces, los pipelines de CI o los portales de autoservicio tienen permiso para crear Kyverno Policies.

Kyverno 1.19.2 se publicó el 20 de octubre de 2026, y sus notas de versión enumeran 24 advisories de seguridad de GitHub: 9 críticos, 14 altos y 1 moderado. Varios de ellos tienen que ver con la validación de rutas de la API y el confinamiento en namespaces. Este advisory se publicó tres días después, el 23 de octubre, pero tanto el advisory como el registro CVE indican 1.19.2 como versión corregida. Cada advisory tiene su propio identificador, así que compruébelos uno por uno en lugar de tratar el conjunto como una sola CVE.

Qué revisar en sus clústeres

Primero, averigüe qué versión de Kyverno se está ejecutando realmente, no la que figura en su repositorio Git:

kubectl get deployments -n kyverno -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}'

Si alguna etiqueta de imagen es v1.19.1, planifique ya la actualización a 1.19.2. Después, revise cuatro aspectos:

  • Quién puede crear Policies de ámbito de namespace. Pruebe directamente las identidades de los tenants y busque roles que concedan policies.kyverno.io, incluidos los ClusterRoles agregados que añaden permisos a los roles integrados admin y edit.
  • Políticas existentes que usan apiCall. Enumérelas y revise cada urlPath, sobre todo las rutas que contengan %, .., ? o #.
  • Configuraciones de webhooks. Compare la lista con lo que espera encontrar. Kyverno crea sus propios webhooks, así que céntrese en los nombres que no reconozca y en las fechas de creación recientes.
  • Logs de auditoría. Busque solicitudes de la ServiceAccount del admission controller de Kyverno que creen configuraciones de webhooks o lean Secrets fuera de su patrón habitual.
kubectl auth can-i create policies.kyverno.io -n team-a --as=system:serviceaccount:team-a:default
kubectl get policies.kyverno.io -A -o json | jq -r '.items[] | select([.spec.rules[]?.context[]? | select(.apiCall)] | length > 0) | "\(.metadata.namespace)/\(.metadata.name)"'
kubectl get mutatingwebhookconfigurations,validatingwebhookconfigurations -o custom-columns=NAME:.metadata.name,CREATED:.metadata.creationTimestamp

Sustituya team-a por los namespaces e identidades de sus propios tenants. Si encuentra un webhook que no sabe explicar en un clúster que ejecutó 1.19.1, trátelo como un posible incidente: conserve los logs de auditoría antes de eliminar nada.

La lección de fondo: audite a quien hace cumplir las reglas

Los admission controllers, los motores de políticas y los operators suelen ser los componentes con más privilegios de un clúster. Necesitan permisos amplios para hacer su trabajo, y los tenants interactúan con ellos a diario. Eso los convierte en un objetivo atractivo. En este caso, el modelo multitenant dependía de una sola comprobación, y bastó un paso de decodificación que la comprobación y la solicitud trataban de forma distinta para romperlo.

En las plataformas Kubernetes de nube privada y multitenant, tres hábitos ayudan. Trate los motores de políticas como parte de la superficie de ataque y siga sus versiones de seguridad con la misma atención que la versión de Kubernetes. Conceda a sus ServiceAccounts solo los permisos que necesitan, por ejemplo, sin otorgar lectura de Secret salvo que alguna política lo requiera. Y revise qué funciones pueden alcanzar los tenants mediante la delegación, porque una función que se ejecuta con los privilegios de la plataforma convierte la entrada de un tenant en una acción de la plataforma.

Fuentes