Voltar
2026/11/10
Kyverno CVE-2026-124440: quando o motor de políticas vira o atalho para cluster admin
No Kyverno 1.19.1, um tenant que pode criar políticas em um namespace consegue chegar a cluster admin. Como o bypass funciona e o que verificar antes de atualizar.
Muitas equipes usam o Kyverno para manter os tenants do Kubernetes isolados entre si. Ele verifica cada objeto em relação às políticas antes que o API server o armazene e pode permitir que os donos de namespaces escrevam suas próprias políticas para o próprio namespace. A CVE-2026-124440, publicada em 8 de novembro de 2026, mostra como essa delegação pode falhar. No Kyverno 1.19.1, um tenant que só pode criar políticas no próprio namespace consegue fazer o Kyverno agir fora desse namespace e, passo a passo, chegar a cluster admin.
A correção está disponível desde 20 de outubro no Kyverno 1.19.2. Clusters que não aplicaram essa versão continuam expostos. Este artigo explica o que deu errado, como funciona a escalada e o que verificar nos seus próprios clusters.
Pontos principais
- A CVE-2026-124440 (advisory do GitHub GHSA-39w8-hv5g-f73w) afeta o Kyverno 1.19.1 e foi corrigida na 1.19.2. O registro da CVE atribui nota 9.4 pelo CVSS 4.0 e 9.9 pelo CVSS 3.1.
- O atacante só precisa de permissão para criar uma Kyverno Policy com escopo de namespace no próprio namespace.
- O apiCall da política é executado com a ServiceAccount do admission controller do Kyverno, que pode ler outros namespaces e criar admission webhooks válidos para todo o cluster. Esse caminho leva a cluster admin.
- O advisory não indica nenhuma solução de contorno. Atualize para a 1.19.2 e depois revise quem pode criar políticas e quais webhooks existem.
- Nas fontes que analisamos, não há relatos de exploração ativa.
O que o namespace clamp deveria fazer
As políticas do Kyverno podem buscar dados na API do Kubernetes enquanto avaliam uma requisição. Esse recurso se chama apiCall: uma regra indica um urlPath, o Kyverno chama o API server e o resultado alimenta a regra. A chamada é feita com a ServiceAccount do próprio Kyverno, e não com as permissões de quem escreveu a política.
Em ClusterPolicies, que valem para todo o cluster e são escritas por administradores da plataforma, isso é esperado. Em Policies com escopo de namespace, que os tenants podem ter permissão para escrever, isso é um risco. Advisories anteriores (GHSA-c5qq-7g2q-cpqp e GHSA-5qq8-67g6-4h2w) mostraram que uma Policy com escopo de namespace podia usar apiCall para ler outros namespaces ou gravar objetos com escopo de cluster. O Kyverno 1.19.1, lançado em 10 de setembro de 2026, adicionou um “namespace clamp”: antes de executar a chamada, o Kyverno verifica se o caminho permanece dentro do namespace da própria política.
Onde a verificação e a ação divergem
O clamp da 1.19.1 não verificava a string que de fato enviava. Segundo o advisory, ele decodificava o percent-encoding do urlPath, normalizava o resultado (de modo que os segmentos .. fossem resolvidos) e verificava o namespace nessa cópia limpa. A requisição em si era então enviada com o caminho original, sem tratamento.
Isso funciona enquanto a decodificação dá certo. Mas, se o caminho contiver um percent-escape malformado, como um % isolado em uma query string no final, a decodificação falha. Nesse caso, o código da 1.19.1 passava a verificar a string bruta, ainda codificada. O API server não tem esse tipo de alternativa: ele decodifica o caminho por completo e roteia a requisição. Assim, o clamp enxerga o namespace do próprio tenant, enquanto o API server enxerga segmentos .. codificados que saem dele, rumo a outro namespace ou a uma coleção com escopo de cluster.
O advisory ressalta que se trata de uma classe de entradas, e não de um único payload. Bloquear uma string literal específica não resolveria o problema. A correção duradoura é validar e executar exatamente o mesmo caminho.
É isso que a 1.19.2 faz. Pela nossa leitura do código-fonte da 1.19.2, o Kyverno agora gera uma forma canônica única do caminho, rejeita caminhos que não consegue canonizar, verifica o namespace nessa forma e envia essa mesma forma ao API server. Um problema semelhante, corrigido na mesma versão, a CVE-2026-122310 (GHSA-3xfv-vq8x-qhg4), explorava a mesma divergência entre a verificação na cópia limpa e a requisição bruta, escondendo segmentos ../ atrás de # ou ?. Trata-se de uma CVE separada, com registro próprio.
A cadeia de escalada, passo a passo
Quem reportou a falha demonstrou a cadeia no Kubernetes 1.31 com o Kyverno 1.19.1 instalado a partir do chart Helm padrão, com os valores default.
- Criar uma Policy com escopo de namespace. O único privilégio do tenant é criar
policies.kyverno.iono próprio namespace. A política contém umapiCallcujo caminho passa pelo clamp, mas é roteado para outro lugar. - Acioná-la. Criar qualquer objeto comum que corresponda à política, como um ConfigMap no namespace do tenant, faz o Kyverno avaliar a regra e executar a chamada com a ServiceAccount do seu admission controller.
- Ler entre namespaces. A mesma técnica permite ler objetos em outros namespaces, inclusive Secrets, se o deployment do Kyverno tiver permissão para lê-los.
- Gravar um webhook para todo o cluster. A ServiceAccount pode criar MutatingWebhookConfigurations e ValidatingWebhookConfigurations, então o tenant consegue registrar seu próprio webhook, que passa a interceptar e reescrever requisições de admissão em todos os namespaces.
- Chegar a cluster admin. O advisory descreve o uso desse webhook para alterar pods criados em kube-system e, a partir daí, conceder ao tenant direitos de cluster-admin. O resultado é a perda total de confidencialidade, integridade e disponibilidade.
Não é necessária nenhuma interação do usuário, e o webhook é acionado pela atividade normal do cluster.
Quem é afetado
O registro da CVE lista o Kyverno 1.19.1 como afetado e a 1.19.2 como não afetada. As versões anteriores à 1.19.1 não têm esse bypass específico, porque nem sequer têm o clamp. Elas são afetadas pelos advisories anteriores que o clamp deveria corrigir, portanto permanecer em uma versão mais antiga não é uma alternativa segura. O risco é maior onde donos de namespaces, pipelines de CI ou portais de autoatendimento têm permissão para criar Kyverno Policies.
O Kyverno 1.19.2 foi lançado em 20 de outubro de 2026, e suas notas de versão listam 24 advisories de segurança do GitHub: 9 críticos, 14 altos e 1 moderado. Vários deles tratam de validação de caminhos da API e de confinamento a namespaces. Este advisory foi publicado três dias depois, em 23 de outubro, mas tanto o advisory quanto o registro da CVE indicam a 1.19.2 como versão corrigida. Cada advisory tem seu próprio identificador, então confira um a um, em vez de tratar o conjunto como uma única CVE.
O que verificar nos seus clusters
Primeiro, descubra a versão do Kyverno que está realmente em execução, e não a que está no seu repositório Git:
kubectl get deployments -n kyverno -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}'
Se alguma tag de imagem for v1.19.1, planeje agora a atualização para a 1.19.2. Em seguida, verifique quatro pontos:
- Quem pode criar Policies com escopo de namespace. Teste diretamente as identidades dos tenants e procure roles que concedam
policies.kyverno.io, incluindo ClusterRoles agregadas que adicionam permissões às roles nativas admin e edit. - Políticas existentes que usam apiCall. Liste-as e revise cada
urlPath, principalmente caminhos que contenham%,..,?ou#. - Configurações de webhook. Compare a lista com o que você espera encontrar. O Kyverno cria seus próprios webhooks, então concentre-se em nomes que você não reconhece e em datas de criação recentes.
- Logs de auditoria. Procure requisições da ServiceAccount do admission controller do Kyverno que criem configurações de webhook ou leiam Secrets fora do padrão 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
Substitua team-a pelos namespaces e identidades dos seus próprios tenants. Se encontrar um webhook que não consegue explicar em um cluster que executou a 1.19.1, trate-o como um possível incidente: preserve os logs de auditoria antes de remover qualquer coisa.
A lição mais ampla: audite quem aplica as regras
Admission controllers, motores de políticas e operators costumam ser os componentes mais privilegiados de um cluster. Eles precisam de permissões amplas para fazer seu trabalho, e os tenants interagem com eles todos os dias. Isso os torna um alvo atraente. Neste caso, o modelo de multitenancy dependia de uma única verificação, e bastou uma etapa de decodificação tratada de forma diferente pela verificação e pela requisição para quebrá-lo.
Para plataformas Kubernetes de nuvem privada e multi-tenant, três hábitos ajudam. Trate os motores de políticas como parte da superfície de ataque e acompanhe as versões de segurança deles com a mesma atenção que dedica à versão do Kubernetes. Dê às ServiceAccounts deles apenas as permissões necessárias, por exemplo, não concedendo leitura de Secret a menos que alguma política exija isso. E revise quais recursos os tenants conseguem acessar por meio da delegação, porque um recurso executado com os privilégios da plataforma transforma a entrada de um tenant em uma ação da plataforma.
Fontes
- Advisory de segurança do Kyverno GHSA-39w8-hv5g-f73w: Escalada para cluster-admin por meio de bypass do namespace clamp do apiCall na v1.19.1 com percent-escape malformado
- Registro da CVE: CVE-2026-124440
- Advisory da VulnCheck: Escalada de privilégios no Kyverno 1.19.1 via bypass do namespace clamp do apiCall
- Correção relacionada na mesma versão, CVE-2026-122310: advisory da VulnCheck e GHSA-3xfv-vq8x-qhg4
- Notas de versão do Kyverno v1.19.2: github.com/kyverno/kyverno/releases/tag/v1.19.2
Global
Japan
Korea
China
Taiwan
Vietnam
Thailand
Indonesia
Spain
France
Germany
Egypt
Russia