KEDA 2.21 corrige CVE 9.9: sua TriggerAuthentication podia virar admin do cluster
Em 23 de setembro de 2026 o projeto KEDA lançou a versão 2.21.0, e o item mais importante do changelog não é nenhum dos três scalers novos — é a correção de GHSA-637c-6jxx-4rwm, CVSS 9.9, descrita pelo próprio time como remediação de uma correção incompleta de uma CVE anterior. Se você usa autenticação Vault via TriggerAuthentication, ou qualquer integração baseada em bound service account token (Prometheus, Datadog Cluster Agent, Metrics API, Loki), isso é atualização prioritária, não item de backlog.
O que aconteceu antes: CVE-2025-68476
Pra entender por que a correção de agora é grave, vale lembrar o que veio antes. CVE-2025-68476 (CVSS 8.2, alta) era uma falha de leitura arbitrária de arquivo: validação insuficiente de path ao carregar o service account token apontado em spec.hashiCorpVault.credential.serviceAccount permitia que um tenant com permissão de criar TriggerAuthentication exfiltrasse conteúdo de qualquer arquivo no node onde o pod do KEDA rodava, redirecionando a leitura pra um endpoint Vault controlado pelo atacante. Foi corrigida nas versões 2.17.3 e 2.18.3.
O que o 2.21.0 corrige: a mesma porta, mais grave
O time do KEDA descreve a nova falha como remediação incompleta daquela CVE. O mecanismo de fundo é o mesmo — TriggerAuthentication como vetor —, mas o alcance é maior: em vez de ler arquivo, agora é escalada de privilégio de admin de namespace pra admin de cluster.
O problema, segundo o advisory:
“The destination address is fully tenant-controlled and unvalidated, and the credential the operator presents defaults to its own ServiceAccount token.”
Em outras palavras: um tenant que só tem permissão de admin dentro do seu próprio namespace consegue criar um TriggerAuthentication que força o operator do KEDA — que roda com permissões de cluster inteiro — a enviar o próprio ServiceAccount token dele para um endpoint escolhido pelo tenant. Como a ServiceAccount do operator do KEDA tem, por padrão, acesso de leitura a Secrets em todos os namespaces e permissão de criar Jobs no cluster, o atacante herda exatamente esse escopo.
Pré-condições pra explorar:
- O tenant tem permissão de criar
TriggerAuthenticationeScaledObjectno próprio namespace (situação comum em setups multi-tenant onde times têm autonomia pra configurar seu próprio autoscaling). - O KEDA está instalado com as configurações padrão.
Com CVSS 3.1 AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H — vetor de rede, baixa complexidade, privilégio baixo necessário, sem interação de usuário, e impacto alto em confidencialidade, integridade e disponibilidade — o impacto documentado inclui: ler todo Secret do cluster, criar e apagar Jobs e HPAs em qualquer namespace, alterar ValidatingWebhookConfiguration e mexer em roteamento de API service. É escalada de namespace admin pra cluster admin de fato, não hipotética.
A correção muda comportamento default — e isso quebra configuração existente
A correção não é só um patch de código: o 2.21.0 muda o default de operator.serviceAccountTokens.mode para enforce-audience. Isso exige que toda autenticação Vault Kubernetes e todo uso de bound service account token (BSAT) declare explicitamente qual audience o token deve carregar — separando o credential que o operator manda pra fora do credential que a própria API do Kubernetes aceita.
Isso é breaking change, não opcional:
- Autenticação Vault Kubernetes — inclui uso do token do operator, um token projetado existente, ou
credential.serviceAccountName— passa a exigir mapeamento de audience explícito. TriggerAuthentication/ClusterTriggerAuthenticationcomboundServiceAccountToken— vale pra qualquer scaler que use esse mecanismo, não só Vault: Metrics API, Prometheus, Loki, Datadog Cluster Agent e outros receivers autenticados por token.- Sem o mapeamento de audience configurado, a autenticação falha — mesmo com o Deployment do KEDA saudável, o scaler específico para de funcionar.
O time recomenda escolher audiences que a própria API do Kubernetes não aceita, justamente pra que um token exposto na integração externa não possa ser reaproveitado contra a API do cluster. Existe uma válvula de escape: operator.serviceAccountTokens.mode: legacy restaura o comportamento antigo (sem audience obrigatória) e emite warning — mas é global, não por TriggerAuthentication, e reintroduz exatamente a superfície que a correção fecha. Trate como ponte de migração, não como configuração permanente.
Além da correção de segurança, o release trouxe três scalers novos (Azure Cosmos DB Change Feed, ClickHouse, GCP Cloud Spanner) e mudança de comportamento no scaler de Azure Pipelines (agora considera jobs em andamento por padrão; scaleOnInFlight: false restaura o comportamento anterior) — mas nenhum dos dois é o motivo de atualizar essa semana.
O que fazer
-
Confirme a versão que você roda. Qualquer coisa anterior ao 2.21.0 está exposta se você usa Vault Kubernetes auth ou BSAT com
TriggerAuthentication. Verifique também charts de terceiros (ex.: Helm chart oficialkedacore/charts) — a versão do chart nem sempre acompanha a do app no mesmo dia. -
Antes de atualizar, leia o guia de migração 2.20 → 2.21. O ponto central é a configuração de audience por receiver — sem isso mapeado, o scaler para de autenticar após o upgrade, e isso pode passar despercebido até o autoscaling de algo crítico parar de reagir.
-
Audite quem tem permissão de criar
TriggerAuthenticationeScaledObjecthoje. Mesmo depois do patch, restringir esse RBAC a operadores de confiança reduz a superfície de qualquer variante futura do mesmo padrão de vulnerabilidade — essa já é a segunda vez que o mesmo vetor aparece. -
Se usar
legacymode como ponte, trate como item com prazo de expiração, não como configuração de produção — documente por que está lá e quando sai. -
Se seu cluster é multi-tenant com times autônomos configurando o próprio
ScaledObject, esse é o tipo de CVE que justifica revisar toda a superfície de autoconfiguração que você delega — não só o KEDA.
Quando isso não é urgente
Se você não usa autenticação Vault Kubernetes nem boundServiceAccountToken em nenhuma TriggerAuthentication — por exemplo, se seus scalers usam só secrets estáticos ou variáveis de ambiente — o vetor específico dessa CVE não se aplica. Ainda vale atualizar pra pegar os scalers novos e os fixes de bug, mas sem a mesma urgência de janela de manutenção.