Mais 123% CVE comunicadas por dia em 2026 do que no ano passado.

SBOM

Uma SBOM deve descrever o build que foi distribuído

Uma SBOM gerada durante o build é registada enquanto o build é executado, a partir do tráfego que realmente entrou nele. Em vez disso, a maioria dos geradores de SBOM reconstrói a lista a posteriori, a partir do lockfile ou do resultado, o que deixa de fora as dependências ocultas que um build obtém por si próprio. Eis porquê, e o que muda ao registar o build.

Atualizado a

What a scanner reads versus what the build pulled in A scanner reads the lockfile, which lists direct packages A, B and C and transitive packages D and E, so its SBOM contains only those. CRACI sees the network traffic into the build job, so its recorded SBOM also contains the hidden dependencies no lockfile lists: code downloaded by an install hook, a download by a build script, and the base image layers. A scanner reads the lockfile package-lock.json direct A B C transitive D E Scanned SBOM A, B, C, D, E only what the lockfile lists CRACI sees the traffic into the build A B C D E install hook download build script download base image layers build job on CRACI Recorded SBOM every package it fetched, hidden too Dashed: hidden dependencies, listed in no lockfile

SBOM de build, SBOM de código-fonte, SBOM analisada

As orientações da CISA sobre tipos de SBOM classificam as SBOM por quando e como são feitas. Três delas cobrem quase todos os geradores de SBOM em uso:

Tipo Como é feita O que pode deixar de fora
Código-fonte A partir de ficheiros de código-fonte, manifestos e lockfiles, normalmente por uma ferramenta de SCA Componentes de runtime, plugins ou plataforma; tudo o que não está declarado nos ficheiros
Build Como parte do build que cria o artefacto a lançar O que o ambiente de build não consegue ver, e é por isso que a completude deve ser indicada
Analisada Depois do build, através da análise de um executável, pacote ou imagem de contentor Componentes que a ferramenta não consegue reconhecer; os resultados dependem de heurísticas

A CISA indica dois benefícios de uma SBOM de build: mais confiança de que a SBOM representa corretamente o artefacto, devido à informação disponível durante o build e o processo de CI/CD, e mais fiabilidade, porque o mesmo workflow de build pode assinar tanto a SBOM como o artefacto. A desvantagem indicada é que pode ter de alterar o processo de build para gerar uma. Com o CRACI, essa alteração é uma linha, runs-on: craci, e o registo vem com o runner.

Analisar uma pasta versus registar um build

A maioria dos geradores de SBOM são scanners. Aponta-se um para uma árvore de código-fonte ou uma imagem de contentor, e este deduz o que pensa que entrou lendo manifestos, lockfiles, pacotes instalados ou binários. Isso é útil e, para software que não compilou, muitas vezes é a única opção.

A fragilidade é que um scanner só vê o que tem à frente. Se não tiver sido feito commit de nenhum lockfile, se as dependências não tiverem sido instaladas antes da análise ou se o produto for distribuído como binário compilado, o scanner tem menos com que trabalhar do que o build teve. Uma análise que não encontra nenhum componente produz na mesma um documento SBOM válido, e é essa a parte que apanha as pessoas desprevenidas.

O CRACI segue uma abordagem diferente. Gera a SBOM dentro do seu próprio runner de CI, pelo que o artefacto distribuído é o artefacto descrito. Não é uma análise executada algures ali perto.

SBOM basics: SPDX, CycloneDX and OpenVEX

O que uma SBOM regista, como os formatos SPDX e CycloneDX diferem na prática e o que o OpenVEX acrescenta sobre se uma vulnerabilidade afeta realmente um produto.

Petteri Pulkkinen e Erika Marttinen em Kubernetes Community Days Helsinki 2026, de 16:50 a 22:05 de SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.

De que depende uma análise

O Syft, o Trivy, o cdxgen, o Microsoft SBOM Tool, a exportação do grafo de dependências do GitHub e a Socket CLI deduzem todos uma SBOM a partir do que conseguem ler. Os padrões abaixo decorrem da forma como estas ferramentas estão documentadas.

As ferramentas discordam sobre o que é um componente

Cada gerador decide por si o que conta como componente e em que ficheiros confiar, pelo que o mesmo commit fixado dá a cada um uma lista diferente.

Parte disso tem a ver com nomes. As ferramentas identificam a mesma GitHub Action com tipos de package URL diferentes, pelo que podem listar a mesma coisa e, ainda assim, não coincidir. Isso também faz parte do problema: uma SBOM que usa um identificador diferente para um componente é mais difícil de cruzar com dados de vulnerabilidades.

Ter instalado primeiro pode importar mais do que a ferramenta

O Express 5.2.1 não faz commit de nenhum lockfile. Apontado para um checkout limpo, um gerador que resolve dependências a partir de lockfiles ou de uma árvore instalada não tem nenhum dos dois à frente, pelo que nenhuma das dependências npm declaradas em package.json chega ao documento. Pode ainda assim devolver uma lista, feita do que mais reconhecer, como GitHub Actions e os ficheiros de workflow que as referem. Nenhuma das ferramentas está avariada.

Numa cópia instalada do mesmo repositório, uma flag do Syft volta a mudar a resposta. A mesma ferramenta, a mesma árvore, a mesma versão. Por conceção, uma análise de diretório do Syft reporta o que um projeto declara, e o cataloger que lê os pacotes instalados não faz parte do conjunto predefinido para diretórios.

Algum software não tem manifesto para ler

O repositório anthropics/claude-code na v2.1.259 não tem qualquer tipo de manifesto de dependências: nenhum package.json, lockfile ou equivalente. O que cada gerador devolve é montado a partir de outros tipos de ficheiros, pelo que a resposta diz mais sobre a ferramenta do que sobre o projeto.

O pacote npm publicado não é muito diferente. @anthropic-ai/claude-code declara zero dependências de runtime e oito pacotes específicos de plataforma que encapsulam um binário pré-compilado. @openai/codex 0.149.1 tem a mesma forma. O que é executado na máquina do programador é um binário compilado em cujo interior nenhum leitor de manifestos consegue ver. Isto não é uma falha de uma ferramenta em particular. É um modelo de distribuição que a análise a posteriori não consegue descrever.

Versões e fornecedores

Quando duas ferramentas encontram o mesmo pacote, nem sempre concordam quanto à sua versão. Uma pode fixar uma GitHub Action a um SHA de commit enquanto outra reporta uma tag de versão. Uma consulta de vulnerabilidades com a versão errada dá uma resposta errada com toda a confiança.

O campo do fornecedor, um dos elementos mínimos da NTIA, fica muitas vezes vazio, porque a maioria dos geradores não tem fonte para ele.

Dependências ocultas: o que nenhuma análise consegue ver

Todas as ferramentas acima partem do lockfile ou do resultado do build e deduzem o que entrou. Um build obtém mais do que isso. Estas dependências ocultas não constam de nenhum lockfile, pelo que uma análise não as consegue encontrar:

  • Hooks de instalação. Os scripts preinstall e postinstall do npm são executados durante a instalação e podem descarregar mais código. Foi assim que o worm Shai-Hulud foi executado.
  • Scripts de build. Os scripts de build de Rust, entre outros, descarregam aquilo de que precisam durante o build.
  • Imagens base. Um build de contentor obtém uma imagem base e as respetivas camadas do sistema operativo, que nenhum lockfile de linguagem lista.
  • Caches e ferramentas de build. Os pacotes restaurados de caches de CI e as ferramentas instaladas por passos de configuração também chegam fora do lockfile.

Analisar o resultado depois não fecha a lacuna. Um binário acabado, sobretudo código compilado como Rust, deixa o scanner a adivinhar o que entrou nele.

Dois builds, duas SBOM

Há uma segunda razão pela qual uma análise não pode substituir o build: a maioria dos builds não é reprodutível. Compile o mesmo commit duas vezes seguidas e não há garantia de obter os mesmos pacotes. Os gestores de pacotes resolvem e instalam pela ordem em que as respostas chegam, o que importa sobretudo quando não há lockfile, como em muitos projetos Python, e os passos de build podem ter a sua própria aleatoriedade. Os builds reprodutíveis byte a byte são possíveis, com ferramentas como o Nix, mas são raros.

Assim, uma SBOM gerada mais tarde, noutra máquina ou a partir de outro build, descreve um build que pode nunca ter sido distribuído. Só a SBOM registada durante o build de CI que produziu uma versão prova o que está em produção.

O que muda ao registar o build

O CRACI vê o tráfego; os scanners não. Executa os seus jobs de GitHub Actions nos seus próprios runners e vê o tráfego de rede que entra em cada build, pelo que a SBOM lista o que o job realmente trouxe, incluindo dependências transitivas e ocultas, e não o que um manifesto diz que deveria ser necessário.

As caches são onde o registo durante o build se torna difícil. Um pacote restaurado de uma cache nunca toca num registo de pacotes, pelo que um proxy por si só não o veria. O CRACI transporta as evidências de dependências com a cache, pelo que os pacotes restaurados de uma cache ficam na SBOM do job que os restaurou. Consulte o que a cache do GitHub Actions esconde.

Os ecossistemas detetados incluem npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk e fontes Git, além de predefinições de descarga de Yocto e OpenEmbedded. Os mirrors npm e PyPI do JFrog Artifactory funcionam. Os metadados de licença declarada são incluídos na exportação. As SBOM são exportadas em CycloneDX e SPDX. A página de geração de SBOM cobre a funcionalidade completa.

Ver o tráfego também funciona na outra direção. Um build precisa de pacotes de fontes conhecidas e publica o seu resultado em locais conhecidos. A política de egress do CRACI permite apenas esses e bloqueia de imediato qualquer outra ligação de saída, pelo que o malware que tente enviar os seus segredos para o servidor de um atacante falha. Como a política permite aquilo de que o build precisa em vez de procurar hosts maliciosos conhecidos, mantém-se mesmo que seja o primeiro alvo de um ataque que ninguém viu antes, como aconteceu com o Shai-Hulud. Consulte como uma política de egress impede a exfiltração.

SBOM de contentores e Docker

É nas imagens de contentor que a diferença mais se nota. As formas habituais de obter uma SBOM de Docker analisam todas a imagem: o Syft e o Trivy analisam-na, docker scout sbom indexa o seu conteúdo quando a imagem não tem nenhuma atestação SBOM, e a atestação SBOM do BuildKit, ativada com --sbom=true, executa por defeito um scanner baseado em Syft sobre a fase final da imagem. O plugin mais antigo docker sbom foi descontinuado em favor de docker scout sbom.

Cada um destes lê a imagem acabada, pelo que vê o que ainda é reconhecível nas camadas. Não vê o que o build obteve pelo caminho. O CRACI regista o job que compila a imagem: as imagens e os pacotes que o job obtém de registos OCI e fontes de pacotes entram na mesma SBOM que o resto do build. Para uma imagem que não compilou, analisá-la continua a ser a opção prática. Consulte o que escapa às SBOM de imagens Docker.

Completude, indicada por job

Uma SBOM registada só é tão boa quanto o registo. Em vez de apresentar todas as SBOM como completas, o CRACI indica a completude de cada job e de cada cache, num de cinco estados:

  • Complete. O CRACI observou evidências completas do job, e todas as caches restauradas estavam completas.
  • Complete with connections. Os requisitos foram cumpridos, mas o job usou uma ou mais ligações de rede personalizadas, pelo que vale a pena rever o que passou por elas.
  • Incomplete. O CRACI identificou uma condição que pode deixar dependências fora da SBOM.
  • Unavailable. O CRACI não conseguiu terminar a avaliação das evidências.
  • Not recorded. O job é anterior à indicação de completude.

A completude é transitiva entre caches. Se um job restaurar uma cache incompleta, a sua SBOM também fica incompleta, e qualquer cache que esse job produza transporta o estado incompleto. Sabe em que SBOM pode confiar e quais precisam de uma segunda análise.

The hard parts: hooks, noise and staying current

Três problemas que a palestra aponta: hooks post-install que obtêm coisas que nenhum manifesto enumera, encontrar as dependências que importam numa lista longa e manter a SBOM atualizada, o que significa gerá-la na CI em cada build.

Petteri Pulkkinen e Erika Marttinen em Kubernetes Community Days Helsinki 2026, de 25:39 a 27:22 de SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.

Proveniência através da API

A SBOM é uma parte do que o CRACI regista para cada job. A API devolve SBOM, traços de rede e proveniência, tudo registado a partir do mesmo build.

Onde um scanner continua a ser a ferramenta certa

O registo durante o build cobre o software que compila. Para uma imagem ou um binário de terceiros que não compilou, um scanner continua a ser a escolha prática, e as ferramentas acima são capazes e amplamente usadas. A questão não é que os scanners sejam maus. É que a SBOM das suas próprias versões deve vir do build que as produziu.

Uma SBOM do CRACI também tem os seus limites. Cobre os jobs executados em runners CRACI, o que hoje significa GitHub Actions em Linux, com outros sistemas de CI no roadmap.

A escolher entre ferramentas? Consulte ferramentas de SBOM comparadas, ou veja como as SBOM geradas durante o build se enquadram no trabalho de conformidade com o CRA. Para o Syft, o Trivy e o cdxgen lado a lado, consulte o que escapa aos geradores de SBOM open source.

SBOM geradas durante o build: perguntas frequentes

O que é uma SBOM gerada durante o build?

Uma SBOM gerada durante o build, a que a CISA chama build SBOM, é gerada como parte da compilação do artefacto a lançar. Em vez de reconstruir depois a lista de componentes a partir de ficheiros, descreve o que o próprio build usou. O CRACI regista-a a partir dos pacotes que cada job de GitHub Actions realmente obteve.

Qual é a diferença entre uma SBOM de build e uma SBOM analisada?

Uma SBOM analisada é gerada depois do build, através da análise de um artefacto como um executável ou uma imagem de contentor, o que geralmente exige heurísticas. Uma SBOM de build é gerada durante o build, a partir da informação que o build tem. As SBOM analisadas funcionam sem acesso ao build, o que as torna a escolha certa para software que não compilou.

Como gero uma SBOM para uma imagem Docker?

Para uma imagem existente, analise-a com um gerador como o Syft, o Trivy ou docker scout sbom. O BuildKit também pode anexar uma atestação SBOM ao compilar, analisando a imagem final. Para registar o que o build de uma imagem trouxe, execute o build num runner CRACI: a SBOM do job cobre as imagens e os pacotes que obteve.

O que são dependências ocultas?

Tudo o que um build obtém e que nenhum lockfile lista: código descarregado por hooks de instalação do npm, ficheiros que os scripts de build de Rust descarregam durante o build, e a imagem base e as respetivas camadas do sistema operativo num build de contentor. As ferramentas que leem o lockfile ou analisam o resultado não as veem. O CRACI regista-as porque vê o tráfego que entra no build.

Porque é que dois builds do mesmo código dão SBOM diferentes?

Porque a maioria dos builds não é reprodutível. O gestor de pacotes resolve e instala pacotes pela ordem em que as respostas chegam, sobretudo sem lockfile, e os passos de build podem ter aleatoriedade. Compile o mesmo commit duas vezes seguidas e o segundo build pode conter pacotes diferentes. Só a SBOM registada durante o build que produziu uma versão prova o que essa versão contém.

Uma SBOM gerada durante o build está sempre completa?

Não automaticamente. Um registo só é tão bom quanto o que consegue observar, pelo que o CRACI indica a completude de cada job e de cada cache: Complete, Complete with connections, Incomplete, Unavailable ou Not recorded. Sabe em que SBOM pode confiar e quais precisam de uma segunda análise.

Uma SBOM gerada durante o build substitui os scanners de SBOM?

Para o software que compila, sim: a SBOM das suas versões deve vir dos builds que as produziram. Para imagens e binários de terceiros que não compilou, um scanner continua a ser a escolha prática. A página Ferramentas de SBOM comparadas analisa as opções.

Que gerador de SBOM usa o CRACI?

Nenhum. O CRACI não analisa ficheiros. Um proxy que reconhece pacotes nos seus runners regista os pacotes que cada job obtém de npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk e fontes Git, além de predefinições de descarga de Yocto e OpenEmbedded, e exporta o resultado em CycloneDX ou SPDX.

Compare uma SBOM do seu próprio build

Marque uma demo e execute um dos seus workflows no CRACI. Coloque a sua SBOM ao lado da que a sua ferramenta atual produz e veja onde diferem.

Marcar demo