Segurança da Cadeia de Suprimentos (Modelos, Dependências)
Visão geral
A segurança da cadeia de suprimentos (supply chain security) para sistemas de inteligência artificial/aprendizado de máquina (AI/ML) é a disciplina de proteger tudo o que você consome e produz no caminho do código-fonte até o modelo implantado (deployed model): dependências (dependencies) de terceiros, conjuntos de dados (datasets), checkpoints pré-treinados (pretrained checkpoints), imagens de contêiner (container images), scripts de build (build scripts), runners de CI/CD (CI/CD runners) e os registros (registries) que armazenam artefatos (artifacts). O objetivo é garantir integridade (integrity) (nada foi adulterado), autenticidade (authenticity) (veio de quem você pensa que veio) e proveniência (provenance) (você consegue rastrear como foi produzido).
Isso importa no aprendizado de máquina porque sistemas modernos raramente são construídos do zero. Pilhas de treinamento e inferência (inference) geralmente obtêm:
- Pacotes Python (PyPI/Conda), bibliotecas CUDA, pacotes de sistema
- Contêineres e imagens base (base images)
- Modelos pré-treinados e tokenizadores (tokenizers) a partir de hubs de modelos
- Scripts “cola” e templates de configuração
- Utilitários de processamento de conjuntos de dados
- Etapas de build que serializam/desserializam (deserialize) objetos complexos (uma armadilha frequente de segurança)
Ataques à cadeia de suprimentos (supply chain attacks) frequentemente contornam defesas centradas no modelo ao comprometer entradas do pipeline em vez do comportamento do modelo em tempo de execução. Eles também se conectam diretamente a tópicos correlatos como Envenenamento de Dados e Portas dos Fundos (Data Poisoning & Backdoors) (corrupção no tempo de treinamento), Modelagem de Ameaças para Apps de LLM (Threat Modeling for LLM Apps) (fronteiras de confiança no nível do sistema) e Testes de Red Team (Red Teaming) (encontrar elos fracos no pipeline).
Modelo de ameaças (threat model): o que pode dar errado?
A segurança da cadeia de suprimentos começa com um modelo de ameaças explícito: quem pode atacar, a que eles podem ter acesso e qual impacto desejam causar.
Objetivos comuns de atacantes
- Execução remota de código (RCE) em ambientes de treinamento/inferência (roubar segredos, movimentar-se lateralmente)
- Adulteração do modelo (portas dos fundos, desempenho degradado, classificação incorreta direcionada)
- Exfiltração de dados (dados de treinamento, prompts, pesos proprietários)
- Ataques de reputação/disponibilidade (quebrar builds, introduzir bugs sutis)
Caminhos de ataque de alta probabilidade
Ataques a dependências
- Typosquatting (typosquatting):
torchtritonvstorch-triton, etc. - Confusão de dependências (dependency confusion): publicar um pacote em um índice público com o mesmo nome de um pacote interno, esperando que o resolvedor puxe o público.
- Conta de mantenedor comprometida: releases legítimos do pacote publicam uma atualização maliciosa.
- Dependência transitiva (transitive dependency) comprometida: você confia em A, mas A depende de B.
Ataques a artefatos e checkpoints
- Checkpoints pré-treinados com backdoor: pesos se comportam normalmente, exceto para padrões-gatilho (conecta-se diretamente a Envenenamento de Dados e Portas dos Fundos).
- Formatos de serialização maliciosos: por exemplo, carregamento baseado em
pickledo Python que executa código durante a desserialização. - Adulteração de tokenizador/configuração: mudanças sutis na tokenização podem alterar drasticamente o comportamento do modelo.
Ataques a CI/CD e pipelines
- Runner de CI comprometido ou agente de build
- Vazamento de segredos em logs
- Envenenamento do registro de artefatos (artifact registry poisoning): enviar uma tag maliciosa de modelo ou imagem “latest”
- Código de pipeline não revisado: por exemplo, job de treinamento baixa e executa scripts da internet
Conceitos-chave: integridade, autenticidade, proveniência
A segurança da cadeia de suprimentos se apoia em três propriedades relacionadas:
- Integridade: os bits que você obteve são exatamente os bits que foram publicados.
- Autenticidade: o publicador é quem você pensa que é (identidade).
- Proveniência: um registro verificável de como o artefato foi construído (entradas, etapas de build, ambiente).
Na prática, isso se mapeia para:
- Fixação por hash (hash pinning) (integridade)
- Assinaturas digitais (digital signatures) (autenticidade + integridade)
- Atestações (attestations) / proveniência de build (build provenance) (proveniência)
Frameworks como SLSA (Supply-chain Levels for Software Artifacts), Sigstore e in-toto são frequentemente usados para cadeias de suprimentos de software; as mesmas ideias se aplicam a artefatos de ML (modelos, tokenizadores, pipelines de features), mesmo que as ferramentas sejam menos maduras.
Protegendo dependências (bibliotecas, contêineres, pacotes de sistema)
1) Fixe versões e trave dependências
Dependências sem fixação são uma porta aberta: “instalar o mais recente” hoje não é “instalar o mais recente” amanhã.
- Use arquivos de bloqueio (lockfiles) (
poetry.lock,requirements.txtcom versões fixadas,conda-lock,package-lock.json). - Prefira identificadores imutáveis (immutable identifiers) quando possível (versões exatas, SHAs de commit (commit SHAs)).
Exemplo: fixação rígida de dependências Python com hashes (evita adulteração e atualizações inesperadas):
# requirements.txt
numpy==1.26.4 \
--hash=sha256:6a0a... \
--hash=sha256:9b12...
requests==2.32.3 \
--hash=sha256:ab34... \
--hash=sha256:cd56...
Instale com:
pip install --require-hashes -r requirements.txt
Isso bloqueia a instalação se o wheel/código-fonte baixado não corresponder a um dos hashes permitidos.
2) Reduza sua superfície de dependências
Cada dependência é uma relação adicional de confiança.
- Remova pacotes não utilizados.
- Prefira bibliotecas bem mantidas com processos de release robustos.
- Evite pacotes de “conveniência” que fazem shell-out para baixar binários no momento da instalação.
- Separe ambientes: treinamento pode exigir mais pacotes do que inferência; não envie dependências apenas de treinamento para produção.
3) Use espelhos/proxies privados e listas de permissão (allowlists)
Para organizações, um padrão comum é:
- Espelhar imagens do PyPI/Conda em um repositório interno controlado
- Permitir apenas pacotes/versões aprovados
- Bloquear saída direta (egress) de produção para índices públicos de pacotes
Isso mitiga confusão de dependências e reduz a exposição a upstreams comprometidos.
4) Varra continuamente (mas não confunda varredura com segurança)
Use ferramentas de varredura (scanners) para encontrar problemas conhecidos, não para garantir segurança:
pip-audit/ scanners baseados em OSV para Pythonnpm auditpara ecossistemas JS- Varredura de contêiner (por exemplo, Trivy, Grype) para CVEs em imagens base
A limitação: scanners em geral detectam vulnerabilidades conhecidas, não pacotes maliciosos porém “limpos”.
5) Reforce a cadeia de suprimentos de contêiner e SO
- Fixe imagens base por digest criptográfico (digest), não por tag:
- Prefira
python@sha256:<digest>em vez depython:3.11
- Prefira
- Mantenha imagens mínimas (distroless, slim) para reduzir a pegada de CVEs.
- Construa imagens em um ambiente controlado; evite padrões
curl | bash. - Separe estágios de build e de runtime (multi-stage builds).
Protegendo modelos e checkpoints (pesos, tokenizadores, configs)
Artefatos de modelo são executados em um sentido mais amplo: eles influenciam computações e podem ser carregados por caminhos de código que são inseguros por padrão.
1) Trate arquivos de modelo como entradas não confiáveis
Um arquivo de modelo vindo da internet é análogo ao download de um binário. Você deveria perguntar:
- Quem publicou?
- Mudou desde a revisão?
- O carregador pode executar código?
Evite formatos inseguros de desserialização (deserialization)
Em Python, pickle não é um formato de dados; é um formato de execução de código. Carregar um objeto serializado com pickle de uma fonte não confiável pode executar código arbitrário.
Orientação prática:
- Prefira formatos mais seguros como
safetensorspara pesos de redes neurais, quando disponível. - Evite padrões como
torch.load()em arquivos.pt/.pthnão confiáveis, a menos que você tenha controles fortes de proveniência.
Exemplo: carregando safetensors:
from safetensors.torch import load_file
state_dict = load_file("model.safetensors") # no pickle execution
Se você precisar usar torch.load, garanta que os arquivos venham de uma fonte confiável e verificada e considere isolar o processo de carregamento (sandbox de contêiner, menor privilégio).
2) Fixe versões de modelo de forma imutável (hash de commit, revisão, digest)
Se você consome artefatos pré-treinados de um hub, fixe em uma revisão (revision) imutável em vez de “latest”.
Exemplo (estilo Hugging Face): fixar por SHA de commit/revisão:
from huggingface_hub import hf_hub_download
path = hf_hub_download(
repo_id="org/model-name",
filename="model.safetensors",
revision="3b2c1f0e5d2a4c0a9a..." # immutable commit
)
Isso evita que mudanças silenciosas no upstream alterem o que você implanta.
3) Verifique integridade com hashes
No mínimo, armazene e verifique SHA-256 para cada modelo que você implanta.
sha256sum model.safetensors > model.safetensors.sha256
sha256sum -c model.safetensors.sha256
Hashes protegem a integridade depois que você decide no que confiar. Eles não dizem quem produziu o artefato; assinaturas resolvem isso.
4) Assine e verifique artefatos (autenticidade)
Use assinatura para vincular um artefato a uma identidade.
Abordagens comuns:
- Sigstore/cosign para imagens de contêiner e blobs
- GPG em alguns ecossistemas (gestão de chaves mais manual)
- Assinatura nativa do registro, se suportada
Exemplo ilustrativo (cosign verificando um artefato ou imagem OCI):
cosign verify --key cosign.pub ghcr.io/org/model-image@sha256:<digest>
Na prática, você também vai querer aplicação de políticas (policy enforcement) (por exemplo, controle de admissão do Kubernetes (Kubernetes admission control)) para que artefatos não assinados não possam ser implantados.
5) Detecte adulteração e portas dos fundos em artefatos de ML
Controles de cadeia de suprimentos visam prevenir adulteração, mas você também deve testar para detectá-la:
- Execute suítes de avaliação contra benchmarks de referência
- Faça verificações direcionadas para padrões-gatilho conhecidos (quando aplicável)
- Compare com estatísticas de ativação esperadas ou linhas de base conhecidas e confiáveis
Isso se sobrepõe a Testes de Red Team e avaliações focadas em portas dos fundos em Envenenamento de Dados e Portas dos Fundos.
Protegendo pipelines de artefatos (treinamento, avaliação, empacotamento, implantação)
1) Proveniência de build e atestações
Um pipeline seguro pode produzir atestações como:
- Qual commit de origem construiu o modelo?
- Quais identificadores de snapshot de dados foram usados?
- Quais dependências (SBOM) estavam presentes?
- Qual runner de CI e workflow de build executaram?
Atestações permitem que verificadores downstream chequem que:
- o build rodou em um ambiente confiável,
- a partir de código revisado,
- com dependências fixadas,
- e produziu o artefato exato que está sendo implantado.
Mesmo que sua organização não adote um programa completo de SLSA imediatamente, você pode aproximar o espírito:
- Registre metadados de build (SHA do git, hashes de lock de dependências)
- Armazene SBOMs (Software Bill of Materials) como artefatos adjacentes
- Exija artefatos assinados para progredir entre etapas do pipeline
2) Proteja runners de CI/CD e infraestrutura de treinamento
Pipelines de ML frequentemente rodam com privilégios altos (acesso a GPU, acesso a data lake). Trate jobs de treinamento como cargas de trabalho de produção.
- Use runners efêmeros (ephemeral runners) (VM/contêiner novo por job)
- Restrinja a saída de rede para build/treinamento quando possível
- Armazene segredos em um gerenciador de segredos; evite tokens de longa duração
- Use funções IAM (Identity and Access Management) de menor privilégio (identidades separadas para treinar vs implantar)
- Registre e monitore eventos de publicação de artefatos (quem enviou o quê, quando)
3) Restrinja registros e armazenamentos de artefatos
Seu registro de modelos (ou bucket) é um alvo de alto valor.
- Use versionamento imutável (sem sobrescrita)
- Desabilite “delete/force push” para artefatos protegidos
- Exija revisão/aprovações para promover de staging para produção
- Mantenha uma trilha de auditoria append-only (somente anexar)
Um padrão comum:
- registro
models-dev(iteração rápida) models-staging(assinado + avaliado)models-prod(assinado + verificado por política + aprovação manual)
4) Torne builds reproduzíveis quando viável
Reprodutibilidade é um espectro em ML por causa de não determinismo (non-determinism) (kernels de GPU, aleatoriedade), mas você ainda pode melhorar:
- Fixe versões exatas de dependências e imagens base
- Rastreie seeds e configs de treinamento
- Versione conjuntos de dados e pipelines de features
- Capture metadados do ambiente (versão do CUDA, driver, tipo de GPU)
Mesmo que os pesos não sejam perfeitamente reproduzíveis, o processo deve ser rastreável e consistente.
Exemplo prático ponta a ponta: endurecendo a ingestão (ingestion) + implantação (deployment) de um modelo de ML
Cenário: você quer implantar um modelo de embeddings (embedding model) pré-treinado de terceiros.
- Selecione uma fonte
- Prefira uma conta oficial de organização ou um publicador amplamente utilizado.
- Revise o histórico do repositório e as práticas de release.
- Fixe e baixe de forma imutável
- Fixe no SHA do commit / revisão imutável.
- Baixe pesos em formato
safetensorsse disponível.
- Verifique integridade
- Armazene SHA-256 no seu repositório interno de metadados.
- Verifique em cada etapa de promoção.
- Varra e avalie
- Rode uma avaliação baseline para detectar regressões inesperadas.
- Rode uma pequena suíte de testes de segurança/comportamento relevante ao seu caso de uso.
- Reempacote em um artefato controlado
- Construa um contêiner mínimo de inferência fixado por digest.
- Inclua apenas dependências de runtime.
- Adicione um pequeno passo de verificação em runtime (checar hashes esperados dos arquivos).
- Assine e publique
- Assine o artefato do contêiner/modelo.
- Publique em um registro interno com tags de versão imutáveis.
- Aplique verificação no momento do deploy
- O sistema de implantação só permite artefatos assinados do seu registro.
- Políticas de admissão bloqueiam tags “latest” e imagens não assinadas.
Esse fluxo evita muitas falhas do mundo real: mudanças silenciosas no upstream, adulteração de artefatos, atualizações maliciosas de dependências e promoção acidental de builds não revisados.
Armadilhas comuns (e como evitá-las)
Usar
latestem todo lugar
Correção: fixe versões, digests e revisões de modelo.Confiar apenas em varredura de vulnerabilidades
Correção: adicione integridade (hashes), autenticidade (assinaturas) e proveniência (atestações).Carregar arquivos de modelo não confiáveis com desserialização insegura
Correção: prefirasafetensors; isole e verifique artefatos; restrinja fontes.Jobs de treinamento com privilégios excessivos
Correção: IAM de menor privilégio; papéis separados; computação efêmera.Nenhuma separação entre registros de dev e prod
Correção: promoção em estágios com aprovações explícitas e gates de política.Nenhuma trilha de auditoria para criação e promoção de artefatos
Correção: logs append-only; metadados de artefatos; proveniência de build assinada.
Como isso se conecta à segurança de ML de forma mais ampla
Segurança da cadeia de suprimentos é uma camada preventiva. Ela reduz a chance de você ingerir componentes comprometidos que depois se manifestam como:
- Portas dos fundos e manipulação no tempo de treinamento (Envenenamento de Dados e Portas dos Fundos)
- Comprometimentos no nível do sistema que permitem extração ou abuso (Modelagem de Ameaças para Apps de LLM)
- Riscos downstream de privacidade e inferência se atacantes obtiverem acesso interno (veja Inferência de Associação, Extração de Dados de Treinamento)
Ela também apoia Testes de Red Team eficazes: se você não consegue rastrear o que implantou, não consegue reproduzir nem corrigir de forma confiável o que encontrou.
Controles de base recomendados (checklist)
Dependências
- Fixe versões e use lockfiles
- Imponha verificação de hashes para dependências Python quando possível
- Use espelhos internos/listas de permissão para fontes de pacotes
- Varredura contínua + processo de atualização
Artefatos de modelo
- Prefira formatos seguros (
safetensors) - Fixe revisões imutáveis (SHA de commit/digest)
- Verifique hashes no download e na promoção
- Assine artefatos para implantação
Pipelines
- Runners de CI efêmeros e reforçados
- Segredos e IAM de menor privilégio
- Registros imutáveis + promoção em estágios
- Registre metadados de proveniência e armazene SBOMs
Governança
- Documente fontes confiáveis e fluxos de aprovação
- Plano de resposta a incidentes para dependências/modelos comprometidos
- Revisões regulares de acesso para registros e sistemas de CI
Direções emergentes
A segurança da cadeia de suprimentos para ML está convergindo com práticas de cadeia de suprimentos de software, mas com desafios específicos de ML (artefatos binários grandes, builds não determinísticos, distribuição guiada por hubs). Áreas ativas incluem:
- Proveniência padronizada para modelos (config de treinamento, linhagem de conjuntos de dados, atestações de avaliação)
- Melhor UX de assinatura e verificação em hubs de modelos e registros
- Aplicação de política como código (policy-as-code) para “somente modelos assinados + atestados podem ser implantados”
- Serialização e comportamento de carregadores mais seguros por padrão em frameworks de ML
Quando bem implementada, a segurança da cadeia de suprimentos transforma “confie em mim” em confiança verificável — para que você possa escalar o desenvolvimento de ML sem escalar o risco.