SBOM
Exemplos de SBOM
A forma mais rápida de perceber uma SBOM é ler uma. Eis a mesma pequena aplicação em CycloneDX e em SPDX, com o significado de cada campo, o aspeto de uma SBOM fraca e a forma de verificar a sua.
Atualizado a
A aplicação destes exemplos
Ambos os ficheiros descrevem example-api 2.4.0, um serviço Node.js ilustrativo com uma dependência direta, express. Por sua vez, o Express depende de accepts, pelo que os exemplos mostram também uma dependência transitiva. Uma SBOM real de uma aplicação Express lista muitos mais componentes, mas a estrutura é a mesma.
Exemplo de SBOM em CycloneDX
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2026-10-30T09:00:00Z",
"lifecycles": [{ "phase": "build" }],
"tools": {
"components": [
{ "type": "application", "name": "example-sbom-tool", "version": "1.0.0" }
]
},
"component": {
"type": "application",
"bom-ref": "example-api",
"name": "example-api",
"version": "2.4.0"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:npm/[email protected]",
"name": "express",
"version": "4.21.2",
"purl": "pkg:npm/[email protected]",
"licenses": [{ "license": { "id": "MIT" } }]
},
{
"type": "library",
"bom-ref": "pkg:npm/[email protected]",
"name": "accepts",
"version": "1.3.8",
"purl": "pkg:npm/[email protected]",
"licenses": [{ "license": { "id": "MIT" } }]
}
],
"dependencies": [
{ "ref": "example-api", "dependsOn": ["pkg:npm/[email protected]"] },
{ "ref": "pkg:npm/[email protected]", "dependsOn": ["pkg:npm/[email protected]"] }
]
}
| Campo | O que lhe diz |
|---|---|
specVersion |
Que versão do formato o ficheiro usa, para que as ferramentas o consigam interpretar. |
serialNumber, version |
Que SBOM é esta e qual a sua revisão. |
metadata.lifecycles |
Quando a SBOM foi criada. Neste caso, durante o build. |
metadata.tools |
Que ferramenta a produziu. Duas ferramentas podem reportar o mesmo commit de formas diferentes. |
metadata.component |
O produto que a SBOM descreve. |
purl |
O package URL, o identificador que permite a uma ferramenta associar o componente aos avisos de segurança. |
licenses |
A licença declarada do componente. |
dependencies |
Quem traz quem. É isto que torna accepts visível como dependência transitiva. |
Exemplo de SBOM em SPDX
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "example-api-2.4.0",
"documentNamespace": "https://example.com/spdx/example-api-2.4.0",
"creationInfo": {
"created": "2026-10-30T09:00:00Z",
"creators": ["Tool: example-sbom-tool-1.0.0"]
},
"packages": [
{
"name": "example-api",
"SPDXID": "SPDXRef-Package-example-api",
"versionInfo": "2.4.0",
"downloadLocation": "NOASSERTION"
},
{
"name": "express",
"SPDXID": "SPDXRef-Package-express",
"versionInfo": "4.21.2",
"downloadLocation": "NOASSERTION",
"licenseDeclared": "MIT",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:npm/[email protected]"
}
]
},
{
"name": "accepts",
"SPDXID": "SPDXRef-Package-accepts",
"versionInfo": "1.3.8",
"downloadLocation": "NOASSERTION",
"licenseDeclared": "MIT",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:npm/[email protected]"
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES",
"relatedSpdxElement": "SPDXRef-Package-example-api"
},
{
"spdxElementId": "SPDXRef-Package-example-api",
"relationshipType": "DEPENDS_ON",
"relatedSpdxElement": "SPDXRef-Package-express"
},
{
"spdxElementId": "SPDXRef-Package-express",
"relationshipType": "DEPENDS_ON",
"relatedSpdxElement": "SPDXRef-Package-accepts"
}
]
}
A informação é a mesma, organizada de outra forma. O SPDX mantém uma lista packages e indica cada ligação entre elementos em relationships. licenseDeclared é o que o pacote diz sobre si próprio, e downloadLocation pode ser NOASSERTION quando a ferramenta não a conhece. Para saber em que diferem os dois formatos para além da estrutura, consulte CycloneDX vs SPDX.
Como é uma SBOM fraca
Um ficheiro pode ser válido e, ainda assim, quase inútil. Esteja atento a estes sinais:
- Sem relações de dependência. Uma lista plana indica que um pacote está presente, mas não o que o trouxe, e é disso que precisa para corrigir uma dependência transitiva.
- Sem package URLs. Sem um identificador como um purl, a associação de um componente aos avisos de segurança fica reduzida a suposições a partir dos nomes.
-
Licenças em falta. Muitos campos deixados como
NOASSERTIONsignificam que a SBOM não consegue responder a perguntas sobre licenças. - Componentes suspeitosamente escassos. Um punhado de componentes para uma aplicação grande significa normalmente que só estão lá as dependências diretas, ou apenas o que um lockfile declarou.
- Nada sobre quando nem como. Sem uma ferramenta e um contexto de geração, não é possível saber até que ponto se pode confiar na cobertura da SBOM.
- Silêncio sobre as lacunas. Uma boa SBOM diz o que não conseguiu ver. A maioria dos ficheiros simplesmente termina, e quem os lê assume que estão completos.
Como verificar a sua SBOM
- Valide o formato. Passe-a por um validador de esquema para o respetivo formato e versão, porque uma ferramenta que não consegue interpretar o ficheiro não o consegue usar.
- Verifique os campos. Compare-a com os 2026 Minimum Elements ou com a lista que o seu cliente pediu.
- Procure algo que conhece. Escolha uma dependência transitiva, um pacote da sua imagem base e uma ferramenta de build, e veja quais aparecem.
- Compare duas fontes. Gere uma segunda SBOM com um método diferente e observe a diferença. Cada componente adicional num ficheiro é uma pergunta sobre o outro.
Uma SBOM do CRACI gerada durante o build
O CRACI exporta os mesmos formatos. O que difere é a origem do conteúdo: regista o que cada job de GitHub Actions obteve, pelo que cada componente da SBOM entrou efetivamente no build, e os pacotes restaurados de caches de CI são assinalados como tal. As GitHub Actions executadas pelo workflow também aparecem como componentes, fixadas no commit usado. A SBOM de cada job tem ainda um estado de completude, para que as lacunas sejam declaradas em vez de ficarem à espera de que as descubra. Consulte geração de SBOM durante o build ou como se comparam as ferramentas de SBOM.
Exemplos de SBOM: perguntas frequentes
Qual é o aspeto de uma SBOM?
Normalmente é um ficheiro JSON, por vezes XML. Começa com dados sobre a própria SBOM, como a ferramenta e a data e hora, depois lista cada componente com o nome, a versão, o identificador e a licença, e por fim descreve como os componentes dependem uns dos outros.
Uma SBOM é um ficheiro JSON?
Normalmente sim, porque o JSON é a codificação mais utilizada tanto do CycloneDX como do SPDX. Ambos os formatos têm também outras codificações, e o SPDX tem ainda uma forma de texto tag-value.
O que é um purl numa SBOM?
Um purl, ou package URL, é um identificador normalizado de um pacote, como pkg:npm/[email protected]. Indica o ecossistema, o pacote e a versão numa única cadeia de caracteres, o que permite às ferramentas associar o componente aos dados de vulnerabilidades de forma fiável.
Quantos componentes deve ter uma SBOM?
Não há um número certo, mas deve incluir as dependências transitivas, que normalmente são muito mais do que as diretas. Muito poucos componentes para uma aplicação grande significam normalmente que a ferramenta só viu parte dela.
É possível ver a SBOM de um projeto open source?
Por vezes. Alguns projetos publicam SBOM com as suas versões, e o GitHub consegue exportar uma a partir do grafo de dependências de um repositório. Essa exportação reflete o que o repositório declara e não o que um build específico usou.
Compare a sua SBOM com uma registada
Execute um workflow de GitHub Actions no CRACI e veja que componentes a sua SBOM atual não lista.
Marcar demo