VORVEX

CVE-2025-33214: quando um workflow de ML vira código no servidor

O NVTabular carregava workflows com cloudpickle sem restringir as classes reconstruídas. Se um artefato não confiável chega ao pipeline, o arquivo passa a executar com a identidade do processo de ML.

Por Equipe Vorvex4 min de leitura

Arquivos de modelo e de workflow costumam atravessar a empresa como se fossem dados: entram por um bucket, passam por um registry e terminam num job com acesso a GPU, datasets e credenciais de nuvem. A CVE-2025-33214 mostra o erro dessa premissa. No NVIDIA NVTabular, carregar um workflow serializado podia executar código no mesmo processo que fazia a carga.

O problema não exige quebrar CUDA nem explorar a GPU. A fronteira falha antes disso, na desserialização de um arquivo workflow.pkl com cloudpickle. Se alguém consegue substituir, publicar ou indicar um artefato que outra pessoa ou automação carregará, o conteúdo deixa de ser apenas configuração e passa a ter a autoridade da identidade que executa o pipeline.

Technical attack path diagram showing an untrusted machine learning workflow artifact moving from a shared model registry into an NVTabular loading process and then reaching cloud credentials, datasets, and compute infrastructure
O artefato atravessa uma fronteira de confiança. O impacto acompanha as permissões do job que chama Workflow.load.

O que a CVE-2025-33214 confirma

A NVIDIA atribuiu CVSS 3.1 de 8,8, severidade alta, com vetor AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H. Em termos práticos, a entrada pode chegar pela rede e a exploração tem baixa complexidade e não exige privilégio prévio, mas depende de uma ação da vítima: o workflow malicioso precisa ser carregado. O impacto potencial inclui execução de código, indisponibilidade, exposição e adulteração de dados.

  • Produto afetado: NVIDIA NVTabular em Linux
  • Componente vulnerável: carregamento de Workflow
  • Versão testada pelo GitHub Security Lab: v23.08.00
  • Abrangência oficial: todas as versões que não incluem o commit 5dd11f4
  • Causa classificada: CWE-502, desserialização de dados não confiáveis

A linha em que dado vira execução

O método Workflow.load resolve o caminho com fsspec e abre workflow.pkl. Na implementação analisada pelo GitHub Security Lab, o objeto era entregue diretamente a cloudpickle.load. Pickle não é um formato passivo: durante a reconstrução, ele pode importar classes e chamar funções. Por isso, conferir extensão ou nome, ou apenas calcular um hash sem uma referência confiável, não muda a natureza do arquivo.

python
# Vulnerable implementation documented by GitHub Security Lab
workflow = cloudpickle.load(
    fs.open(fs.sep.join([path, "workflow.pkl"]), "rb")
)

# Fix in commit 5dd11f4
from nvtabular.tools.serialization import load as load_safe

workflow = load_safe(
    fs.open(fs.sep.join([path, "workflow.pkl"]), "rb")
)
A mudança central substitui a carga irrestrita por um Unpickler que só admite imports cadastrados numa lista permitida.

A correção adiciona um Unpickler próprio e sobrescreve find_class. Quando o pickle tenta reconstruir uma classe ou função fora da lista permitida, a carga termina com erro. É uma diferença pequena no ponto de chamada, mas muda a pergunta de segurança de 'o que este arquivo quer importar?' para 'esta importação foi explicitamente autorizada?'.

Split technical diagram comparing unrestricted pickle deserialization that can invoke arbitrary functions with allowlisted deserialization that blocks an unapproved import at a security boundary
Antes, o artefato escolhia o que o processo importava. Depois da correção, imports fora da lista permitida são bloqueados na desserialização.

O vetor real é a cadeia de artefatos

O CVSS registra interação do usuário porque alguém ou algum job precisa carregar o workflow. Isso não reduz o cenário a phishing manual. Em ambientes de ML, a ação pode ser um notebook aberto por um pesquisador, uma promoção automática entre buckets, um job de validação ou um serviço que recebe o caminho do modelo. O teste relevante é descobrir quem pode gravar ou apontar o artefato e qual identidade o consome.

  • Registry ou bucket permite publicação por identidades que não deveriam influenciar produção
  • Pipeline promove artefatos sem assinatura, proveniência ou hash fixado
  • Notebook compartilhado carrega workflows de diretórios graváveis por outros usuários
  • Job de inferência ou preparação de dados roda com credenciais mais amplas que o necessário
  • Logs registram a execução do job, mas não o digest e a origem exata do artefato carregado

Como testar sem executar um pickle malicioso

Num pentest, não precisamos colocar uma carga de execução num ambiente compartilhado para provar o risco. Primeiro confirmamos a versão do código e o ponto de carga por inspeção estática. Depois mapeamos permissões de escrita e leitura do registry, identidade do consumidor e promoção entre ambientes. Uma prova segura pode usar um artefato inválido e inerte para demonstrar que uma origem sem confiança alcança o loader, sem incluir opcode capaz de chamar o sistema operacional.

bash
# Run in the NVTabular checkout used to build the image.
# These commands only read code and Git history.

rg -n 'cloudpickle\.load|load_safe' nvtabular/workflow/workflow.py

if git merge-base --is-ancestor 5dd11f4 HEAD; then
  echo 'fix 5dd11f4 is present in history'
else
  echo 'fix 5dd11f4 was not confirmed in this checkout'
fi

git rev-parse HEAD
Triagem local e não destrutiva. Em imagem empacotada sem metadados Git, compare o código-fonte do loader e o digest da imagem com o artefato aprovado pela equipe.

Encontrar load_safe é evidência útil, mas não encerra a análise. O binário ou contêiner em produção precisa corresponder ao código revisado, e a lista de classes permitidas também merece inspeção. Em desserialização, cada nova classe autorizada amplia novamente a superfície disponível durante a reconstrução.

Correção e contenção

A orientação oficial é atualizar para uma branch que inclua o commit 5dd11f4 ou posterior. A NVIDIA não identifica uma versão numerada corrigida no boletim, então conferir apenas a versão exibida pelo pacote pode ser insuficiente. É preciso validar o commit incorporado, a imagem de contêiner aprovada ou a confirmação equivalente fornecida pelo mantenedor da distribuição usada.

  • Atualize o NVTabular para código que contenha 5dd11f4 ou posterior e reconstrua as imagens derivadas
  • Invalide workflows de origem desconhecida e republique artefatos a partir de um pipeline confiável
  • Exija digest imutável, assinatura e proveniência antes da promoção para produção
  • Separe quem publica artefatos de quem autoriza sua execução em ambientes privilegiados
  • Reduza credenciais, mounts e acesso de rede do processo que carrega workflows
  • Registre digest, origem, identidade publicadora e identidade consumidora em cada carga

A lição para qualquer pipeline de ML

CVE-2025-33214 é específica do NVTabular, mas o padrão é maior: modelo, checkpoint e workflow serializado podem conter comportamento, não só pesos ou configuração. Se o processo de ingestão confia na extensão do arquivo e o processo de execução confia no loader, a cadeia inteira delega execução a quem controla o artefato.

Um pentest desse ambiente precisa seguir o caminho completo do objeto, da publicação ao runtime. A pergunta decisiva não é apenas 'o pacote está corrigido?', mas 'quem consegue fazer este processo privilegiado carregar o quê?'. É nessa ligação entre storage, identidade, automação e runtime que uma falha de desserialização vira comprometimento de infraestrutura.

← Voltar ao blog

Quer essa mesma profundidade aplicada ao seu ambiente?

Conte o que você precisa validar e a equipe monta um escopo de pentest sob medida.

Falar no WhatsApp

Pronto para avaliar o risco da sua empresa?