A CycloneDX CBOM is an ordinary CycloneDX BOM whose components include the type cryptographic-asset, each carrying a cryptoProperties object that says whether it is an algorithm, a certificate, a protocol or related crypto material such as a key. Libraries link to the crypto they implement with provides, applications link to what they use with dependsOn, and the open source cdxgen tool can generate one from source, keystores or a traced run.
The rest of this post walks every crypto field in the CycloneDX 1.7 schema, shows a complete CBOM for a small service that validates against that schema, and explains how to generate, check and use one for a post-quantum migration plan. For the basics (what a CBOM is and how it differs from an SBOM), start with What is a CBOM, and how is it different from an SBOM?.
Key takeaways
- There is no separate CBOM format. A CBOM is a CycloneDX BOM (1.6 or later) with
cryptographic-assetcomponents, kept inside your SBOM or shipped as its own document. - Each crypto asset has one required property,
assetType:algorithm,certificate,protocolorrelated-crypto-material, each with its own properties object. - Algorithms record a primitive, a registry family, a parameter set, mode, padding, functions, a classical security level in bits and a NIST quantum security category, where 0 means none.
providesmeans a library implements something.dependsOnmeans something uses it. The schema says implementing does not mean in use.- CycloneDX 1.7 (21 October 2025, the basis of ECMA-424 second edition) added registry backed families and curves, certificate lifecycle fields and one
relatedCryptographicAssetslink, and deprecated several 1.6 fields. - cdxgen, under the CycloneDX GitHub organisation, generates CBOMs statically (
cbom) and from a traced run (tracebom). - A CBOM cannot see crypto negotiated with peers you did not trace, the inside of an HSM, or third party services.
- Safeguard does not generate CBOMs or a cryptographic inventory. Its fit is indirect, explained below.
Where CBOM sits in the CycloneDX specification
The CycloneDX capability page describes CBOM as a way to "discover, manage, and report on cryptographic assets in preparation for a quantum-safe future," and ties it to post-quantum readiness, including the US National Security Memorandum on post-quantum cryptography.
CBOM is not an add-on schema. The CycloneDX Authoritative Guide to CBOM describes it as native to CycloneDX: crypto assets are one more component type, and the dependency model gains a way to say what a component implements. Two consequences follow. Any tool that reads CycloneDX JSON can parse a CBOM, even if it ignores cryptoProperties. And you choose where crypto data lives: the guide says CBOM data "can be present in existing xBOMs or externalized into dedicated CBOMs," which matters because a CBOM reveals more about your security posture than an SBOM, so it may need tighter access. BOM-Link lets a separate CBOM point back at components in your SBOM.
Version timeline
Dates come from the CycloneDX specification's GitHub releases page, the Ecma page for ECMA-424, the revision table in the CBOM guide and the registry file.
| Date | Release | What changed for CBOM |
|---|---|---|
| 26 June 2023 | CycloneDX 1.5 | No crypto support; the 1.5 schema has no cryptographic-asset type |
| 9 April 2024 | CycloneDX 1.6 | Adds cryptographic-asset, cryptoProperties with four asset types, and provides dependencies. CBOM guide first edition. |
| 21 October 2025 | CycloneDX 1.7 | Adds algorithmFamily and ellipticCurve from a cryptography registry, certificate lifecycle and extensions, relatedCryptographicAssets, TLS groups and signature schemes, more protocols, the key-wrap primitive; deprecates several 1.6 fields. CBOM guide second edition. |
| December 2025 | ECMA-424 second edition | Ecma's standard defines CycloneDX 1.7, including "domain-specific modelling for cryptographic artefacts" |
| 24 February 2026 | Cryptography registry | lastUpdated value in cryptography-defs.json at the time of writing |
| 2 June and 17 September 2026 | CycloneDX 1.7.1 and 1.7.2 | Patch releases labelled as schema alignment fixes |
The field walk below uses bom-1.7.schema.json from the specification repository's main branch as of 23 October 2026. Diff against the current file before you build tooling on it. Our CycloneDX 1.7 walkthrough covers the rest of 1.7.
The four cryptographic asset types
A cryptographic asset is a component with "type": "cryptographic-asset". All crypto specific data lives in cryptoProperties, which requires only assetType. The schema notes that algorithms and protocols usually live in crypto libraries but may be hardcoded elsewhere, while certificates, keys, tokens, secrets and passwords are the other assets worth modelling.
assetType value | Properties object | Use it for | Example names |
|---|---|---|---|
algorithm | algorithmProperties | A specific algorithm variant with parameters | AES-128-GCM, SHA-256, ML-KEM-768 |
certificate | certificateProperties | A certificate your software ships, loads or presents | a server certificate, an internal CA root |
protocol | protocolProperties | A protocol and version with its suites or transforms | TLS 1.3, SSH, IKEv2, QUIC |
related-crypto-material | relatedCryptoMaterialProperties | Keys, tokens, nonces, salts, passwords, signatures | a TLS private key, a JWT signing key |
One more field applies to every type: oid, the asset's object identifier. Names vary between tools (x25519, X25519, Curve25519); OIDs do not, so they are the safest join key.
Algorithm properties
| Field | Type | Values or meaning |
|---|---|---|
primitive | enum | drbg, mac, block-cipher, stream-cipher, signature, hash, pke, xof, kdf, key-agree, kem, ae, combiner, key-wrap (new in 1.7), other, unknown |
algorithmFamily | enum (1.7) | One of 93 registry families, such as AES, SHA-2, ECDH, ECDSA, RSASSA-PSS, ML-KEM, ML-DSA, SLH-DSA, LMS, XMSS |
parameterSetIdentifier | string | 128 in AES-128, 256 in SHA-256, SHA2-128s in SLH-DSA |
ellipticCurve | enum (1.7) | One of 246 registry curves as namespace/name, such as nist/P-256 or other/Curve25519 |
curve | string | Deprecated in 1.7 |
executionEnvironment | enum | software-plain-ram, software-encrypted-ram, software-tee, hardware, other, unknown |
implementationPlatform | enum | generic, x86_32, x86_64, ARM v7, v8 and v9 profiles, s390x, ppc64, ppc64le, other, unknown |
certificationLevel | array of enum | none, FIPS 140-1, 140-2 and 140-3 levels 1 to 4, Common Criteria EAL1 to EAL7 with plus variants, other, unknown |
mode | enum | cbc, ecb, ccm, gcm, cfb, ofb, ctr, other, unknown |
padding | enum | pkcs5, pkcs7, pkcs1v15, oaep, raw, other, unknown |
cryptoFunctions | array of enum | generate, keygen, encrypt, decrypt, digest, tag, keyderive, sign, verify, encapsulate, decapsulate, other, unknown |
classicalSecurityLevel | integer | Classical security in bits |
nistQuantumSecurityLevel | integer | NIST post-quantum security category; 0 means none is met |
How parameters, modes, primitives and quantum levels are recorded
The guide's design notes explain the detail: the family (AES) is not enough, because security level and even the primitive follow from the variant. AES-128-GCM is authenticated encryption; AES-128-ECB is not. So the schema splits a variant into parts. The component name carries the full variant string, following the registry's naming pattern. algorithmFamily and parameterSetIdentifier pick the family and variant. mode and padding capture block cipher operation, where many weak configurations hide. primitive says what the algorithm is for. The two security levels turn the variant into numbers you can filter.
The registry patterns use a small grammar: square brackets for optional parts, parentheses for choices, a vertical bar for alternatives and curly braces for placeholders. Real entries from cryptography-defs.json:
AES AES[-(128|192|256)][-(ECB|CBC|CFB(1|8|64|128)|OFB|CTR|XTS|CTS)][-{padding}][-{ivlen}] block-cipher
SHA-2 SHA-(224|256|384|512|512/224|512/256) hash
ECDSA ECDSA[-{ellipticCurve}][-{hashAlgorithm}] signature
ECDH ECDH[E][-{ellipticCurve}] and x25519|x448 key-agree
ML-KEM ML-KEM-(512|768|1024) kem
ML-DSA ML-DSA-(44|65|87) signature
SLH-DSA SLH-DSA-(SHA2|SHAKE)-(128s|128f|192s|192f|256s|256f) signature
Each family also lists its standards: ML-KEM points to FIPS 203, ML-DSA to FIPS 204, SLH-DSA to FIPS 205 and AES to FIPS 197.
For quantum levels, the guide's own examples give typical values: AES-128-GCM at category 1, ML-DSA-44 at 1, ML-KEM-768 at 3, ML-KEM-1024 at 5, and RSA, ECDH on secp521r1 and x25519 at 0. These are producer supplied values, not computed by the schema, and they describe the algorithm, not your key handling.
Certificate properties
Version 1.6 had subject, issuer, validity dates, a signature algorithm reference, a public key reference, format and file extension. Version 1.7 adds a lot:
| Field | Purpose |
|---|---|
serialNumber | CA assigned serial number (1.7) |
subjectName, issuerName | Distinguished names |
notValidBefore, notValidAfter | ISO 8601 validity window |
certificateFormat, certificateFileExtension | For example X.509 and crt; the file extension field replaces certificateExtension |
fingerprint | Hash of the certificate excluding its signature (1.7) |
certificateState | Lifecycle states pre-activation, active, suspended, deactivated, revoked, destroyed, with optional reason, or a custom state (1.7) |
creationDate, activationDate, deactivationDate, revocationDate, destructionDate | Lifecycle timestamps (1.7) |
certificateExtensions | Ten common extensions by name (basicConstraints, keyUsage, extendedKeyUsage, subjectAlternativeName and others) with a value, or custom extensions (1.7) |
relatedCryptographicAssets | Links to the signature algorithm and public key, replacing two deprecated reference fields (1.7) |
The guide's case for validity data is simple: an RSA certificate expiring next week is less cryptographic risk than the same certificate valid for 20 more years, and an expired certificate is also an outage.
Protocol properties
type: in 1.7 one oftls,ssh,ipsec,ike,sstp,wpa,dtls,quic,eap-aka,eap-aka-prime,prins,5g-aka,other,unknown. Version 1.6 stopped atwpa.version: a string such as1.3.cipherSuites: each suite has aname,algorithms(bom-refs to algorithm assets),identifiers(code points such as0x13,0x01), and in 1.7tlsGroupsandtlsSignatureSchemes.ikev2TransformTypes: the RFC 7296 transform types (encr,prf,integ,ke) plusesnandauth. In 1.7 each is an array of small objects, such as an encryption entry withname,keyLengthand analgorithmreference.relatedCryptographicAssets: replaces the deprecatedcryptoRefArray.
The guide explains why suites get their own structure: one protocol can negotiate several suites, each built from several algorithms, and the suite array keeps that subtree inside the protocol asset.
Related crypto material properties
| Field | Values or meaning |
|---|---|
type | private-key, public-key, secret-key, key, ciphertext, signature, digest, initialization-vector, nonce, seed, salt, shared-secret, tag, additional-data, password, credential, token, other, unknown |
id | Your identifier, such as a KMS key ID |
state | pre-activation, active, suspended, deactivated, compromised, destroyed, which the schema ties to NIST SP 800-57 key states |
creationDate, activationDate, updateDate, expirationDate | Lifecycle timestamps |
value | The material's value (see Common mistakes) |
size, format | Size in bits; format such as PEM, DER, P8 |
securedBy | mechanism (schema examples: HSM, TPM, SGX, Software, None) and optional algorithmRef |
fingerprint, relatedCryptographicAssets | New in 1.7; the link replaces the deprecated algorithmRef |
Keys can be compromised; certificates can be revoked. Our post on what to record in a cryptographic key inventory covers the inventory practice.
The 1.6 to 1.7 field changes
| 1.6 field | In 1.7 | Use instead |
|---|---|---|
algorithmProperties.curve | Deprecated | ellipticCurve (registry enum) |
| (none) | New | algorithmFamily (registry enum) |
certificateProperties.signatureAlgorithmRef, subjectPublicKeyRef | Deprecated | relatedCryptographicAssets |
certificateProperties.certificateExtension | Deprecated | certificateFileExtension |
relatedCryptoMaterialProperties.algorithmRef | Deprecated | relatedCryptographicAssets |
protocolProperties.cryptoRefArray | Deprecated | relatedCryptographicAssets |
| IKEv2 transform reference arrays | Deprecated form | Arrays of ikeV2Enc, ikeV2Prf, ikeV2Integ, ikeV2Ke, ikeV2Auth objects |
One quirk: the type field of a related asset link is free text, with examples publicKey, privateKey and algorithm, and its description appears copied from securedBy. Because it is not an enum, two generators can write different strings for the same relationship. Pick a convention and normalise on ingest.
How dependencies link code to crypto: uses versus implements
Since 1.6, a CycloneDX dependencies entry can carry two arrays. dependsOn means "uses", the classic SBOM relationship. provides means "implements": the 1.7 schema describes it as the specifications or standards a component provides or implements, with a crypto library implementing an algorithm as the example, and adds that implementing something "does not imply that the implementation is in use."
That sentence is the reason for two edge types. A general purpose crypto library implements dozens of algorithms, including weak ones kept for compatibility. Treat every implemented algorithm as used and every application linking that library appears to use MD5 and DES. The guide's example: an application dependsOn a crypto library, and the library provides AES-128-GCM while depending on another library.
| Edge | Written as | Read as |
|---|---|---|
| Application to library | dependsOn | The app links or loads this library |
| Library to algorithm or protocol | provides | The library contains an implementation |
| Application or protocol to algorithm | dependsOn | This code path actually uses the algorithm |
A tool that only sees which libraries are present can honestly write the first two. Only source analysis, configuration analysis or a runtime trace justifies the third. When you read someone else's CBOM, check which edges it contains before trusting its "in use" story.
A worked CBOM for a small service
This is a complete CBOM for a fictional service, orders-api 2.3.0, that terminates TLS 1.3 through a linked crypto library (library name and version are illustrative). It records one library implementing five crypto assets, a TLS 1.3 protocol with one cipher suite, four algorithms, the server certificate, its public key and a private key reference with no value.
It validates with zero errors against the CycloneDX 1.7 JSON schema (bom-1.7.schema.json with its referenced cryptography-defs.schema.json, spdx.schema.json and jsf-0.82.schema.json), checked with a JSON Schema draft 7 validator on 23 October 2026. Declared as 1.6, the same document fails, because algorithmFamily, ellipticCurve, tlsGroups, tlsSignatureSchemes, the new certificate fields and relatedCryptographicAssets do not exist in 1.6.
{
"bomFormat": "CycloneDX",
"specVersion": "1.7",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2026-10-23T09:00:00Z",
"component": {
"type": "application",
"bom-ref": "orders-api",
"name": "orders-api",
"version": "2.3.0"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:generic/openssl@3.0.15",
"name": "openssl",
"version": "3.0.15",
"purl": "pkg:generic/openssl@3.0.15"
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/protocol/tls@1.3",
"name": "TLS 1.3",
"cryptoProperties": {
"assetType": "protocol",
"protocolProperties": {
"type": "tls",
"version": "1.3",
"cipherSuites": [
{
"name": "TLS_AES_128_GCM_SHA256",
"algorithms": ["crypto/algorithm/aes-128-gcm", "crypto/algorithm/sha-256"],
"identifiers": ["0x13", "0x01"],
"tlsGroups": ["x25519"],
"tlsSignatureSchemes": ["ecdsa_secp256r1_sha256"]
}
]
}
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/aes-128-gcm",
"name": "AES-128-GCM",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "ae",
"algorithmFamily": "AES",
"parameterSetIdentifier": "128",
"mode": "gcm",
"executionEnvironment": "software-plain-ram",
"implementationPlatform": "x86_64",
"certificationLevel": ["none"],
"cryptoFunctions": ["encrypt", "decrypt"],
"classicalSecurityLevel": 128,
"nistQuantumSecurityLevel": 1
},
"oid": "2.16.840.1.101.3.4.1.6"
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/sha-256",
"name": "SHA-256",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "hash",
"algorithmFamily": "SHA-2",
"parameterSetIdentifier": "256",
"executionEnvironment": "software-plain-ram",
"implementationPlatform": "x86_64",
"cryptoFunctions": ["digest"]
},
"oid": "2.16.840.1.101.3.4.2.1"
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/x25519",
"name": "x25519",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "key-agree",
"algorithmFamily": "ECDH",
"ellipticCurve": "other/Curve25519",
"executionEnvironment": "software-plain-ram",
"implementationPlatform": "x86_64",
"cryptoFunctions": ["keygen", "keyderive"],
"classicalSecurityLevel": 128,
"nistQuantumSecurityLevel": 0
},
"oid": "1.3.101.110"
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/ecdsa-p256-sha256",
"name": "ECDSA-P-256-SHA-256",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "signature",
"algorithmFamily": "ECDSA",
"ellipticCurve": "nist/P-256",
"executionEnvironment": "software-plain-ram",
"implementationPlatform": "x86_64",
"cryptoFunctions": ["sign", "verify"],
"classicalSecurityLevel": 128,
"nistQuantumSecurityLevel": 0
},
"oid": "1.2.840.10045.4.3.2"
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/certificate/orders.example.com",
"name": "orders.example.com",
"cryptoProperties": {
"assetType": "certificate",
"certificateProperties": {
"serialNumber": "4f:2a:91:0c:7e:13:55:a8",
"subjectName": "CN=orders.example.com",
"issuerName": "CN=Example Issuing CA 2,O=Example Corp",
"notValidBefore": "2026-09-01T00:00:00Z",
"notValidAfter": "2026-11-30T23:59:59Z",
"certificateFormat": "X.509",
"certificateFileExtension": "crt",
"certificateState": [{ "state": "active" }],
"certificateExtensions": [
{ "commonExtensionName": "keyUsage", "commonExtensionValue": "digitalSignature" },
{ "commonExtensionName": "extendedKeyUsage", "commonExtensionValue": "serverAuth" },
{ "commonExtensionName": "subjectAlternativeName", "commonExtensionValue": "DNS:orders.example.com" }
],
"relatedCryptographicAssets": [
{ "type": "algorithm", "ref": "crypto/algorithm/ecdsa-p256-sha256" },
{ "type": "publicKey", "ref": "crypto/key/orders-tls-public" }
]
}
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/key/orders-tls-public",
"name": "orders-tls-public-key",
"cryptoProperties": {
"assetType": "related-crypto-material",
"relatedCryptoMaterialProperties": {
"type": "public-key",
"id": "orders-tls-2026-09",
"state": "active",
"size": 256,
"format": "PEM",
"creationDate": "2026-08-31T12:00:00Z",
"activationDate": "2026-09-01T00:00:00Z",
"expirationDate": "2026-11-30T23:59:59Z",
"relatedCryptographicAssets": [
{ "type": "algorithm", "ref": "crypto/algorithm/ecdsa-p256-sha256" }
]
}
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/key/orders-tls-private",
"name": "orders-tls-private-key",
"cryptoProperties": {
"assetType": "related-crypto-material",
"relatedCryptoMaterialProperties": {
"type": "private-key",
"id": "orders-tls-2026-09",
"state": "active",
"size": 256,
"securedBy": { "mechanism": "Software" },
"relatedCryptographicAssets": [
{ "type": "algorithm", "ref": "crypto/algorithm/ecdsa-p256-sha256" }
]
}
}
}
],
"dependencies": [
{
"ref": "orders-api",
"dependsOn": [
"pkg:generic/openssl@3.0.15",
"crypto/protocol/tls@1.3",
"crypto/certificate/orders.example.com"
]
},
{
"ref": "pkg:generic/openssl@3.0.15",
"provides": [
"crypto/protocol/tls@1.3",
"crypto/algorithm/aes-128-gcm",
"crypto/algorithm/sha-256",
"crypto/algorithm/x25519",
"crypto/algorithm/ecdsa-p256-sha256"
]
},
{
"ref": "crypto/protocol/tls@1.3",
"dependsOn": [
"crypto/algorithm/aes-128-gcm",
"crypto/algorithm/sha-256",
"crypto/algorithm/x25519",
"crypto/algorithm/ecdsa-p256-sha256"
]
}
]
}
What to notice:
- Readable, stable bom-refs. The spec only requires uniqueness within the BOM; the guide suggests a package URL where one exists and a UUID otherwise. For crypto assets, a stable readable path like
crypto/algorithm/x25519makes diffs far easier. - Both edge types. The library
providesfive assets; the application and protocoldependsOnwhat is in use. If the library also implemented SHA-1, it would appear underprovidesonly. - Two levels of linkage. The suite references its algorithms inside
protocolProperties, and the dependency graph repeats that use so a generic graph walker still finds the edge. - No secret values. The private key carries only an
id.securedByset toSoftwareis itself a finding: the key is not hardware protected. - The migration line. Both public key algorithms carry quantum category 0.
Generating a CBOM with open source tools
The CycloneDX capability page links to the CycloneDX Tool Center. This post covers cdxgen in depth because it sits under the CycloneDX GitHub organisation and documents its CBOM support in its own repository. Features below are as its README and docs state them on 23 October 2026, when the latest npm release was 13.4.0 (published 14 October 2026).
What cdxgen detects
- The
cbomcommand is cdxgen with crypto, evidence and deep mode switched on and CycloneDX 1.7 output. The README lists CBOM support for "Java keystores and certificates, plus JavaScript and TypeScript source-level algorithm inventory." It rejects theosproject type and points you toobom. - Source derived algorithms. For JavaScript and TypeScript, cdxgen follows constants through common
node:crypto, WebCrypto and JWT call sites. In thecdxishell,.cryptoslists all crypto assets and.sourcecryptosonly source derived ones. - Containers and root filesystems. With the packaged helpers installed, container and rootfs BOMs gain crypto asset components for keyrings and CA stores.
- Crypto in a normal run.
cdxgen --include-cryptoadds crypto to ordinary generation. Thecryptographic-assettype needs spec 1.6 or newer and is pruned if you downgrade output. - The
tracebomcommand runs a command in a sandbox and records what it loads and negotiates: TLS protocols with cipher suites, plus the bulk ciphers and key exchange groups behind them, each with an OID. A hybrid group such asX25519MLKEM768is recorded as its two halves,x25519andml-kem-768. Loaded crypto libraries get acdx:dynamic:cryptoLibraryproperty.
Static versus traced generation
| Approach | What it sees | What it misses | cdxgen entry point |
|---|---|---|---|
| Static source analysis | Algorithms and parameters at call sites in supported languages | Algorithms chosen at runtime or by a peer; unsupported languages | cbom or cdxgen --include-crypto |
| Keystore and certificate parsing | Certificates and keys in files the scan can read | Keys in HSMs or remote KMS; certificates fetched at runtime | cbom -t java, container and rootfs scans |
| Runtime tracing | TLS version, suites and groups negotiated during the run; libraries loaded | Code paths and peers the run did not touch | tracebom --trace-crypto |
| Hand authoring | Anything you know, such as HSM backed keys or a vendor's stated configuration | Anything you forget; drifts as code changes | An editor and the schema |
Most teams need more than one row: static analysis for coverage, tracing for ground truth, hand authoring for the gaps.
Step by step: generate, validate and query a CBOM
These commands come from the cdxgen and CycloneDX CLI documentation. None write outside the output files you name.
1. Install cdxgen. The npm package was renamed to @cdxgen/cdxgen in version 13. The README's install line:
npm install -g @cdxgen/cdxgen --ignore-scripts --min-release-age=2
For CI and production the README recommends standalone release binaries, verified by hash. The standalone cbom binary bundles its analysis engine; some platform builds still need Java 23 or newer, as the README lists.
2. Generate a static CBOM.
# Java: keystores and certificates
cd /path/to/java-service
cbom -t java -o cbom.json .
# JavaScript or TypeScript: add source derived algorithms to a normal run
cdxgen --include-crypto -o cbom.json /absolute/path/to/js-project
3. Add a traced CBOM from a real run. Choose a command that exercises the paths you care about:
tracebom --cmd "npm test" --trace-crypto -o cbom-runtime.json
The tracebom guide says Linux crypto tracing uses eBPF on kernel 5.8 or newer, and the deeper operations probe mode (digest, encrypt and sign calls) is Linux only. On Windows, crypto DLL tracing needs an elevated prompt, and runtimes with built in TLS (the guide names Node.js, Go, Rust and Java) load no crypto DLLs, so TLS parameters come from the egress proxy mode. Pass --strict in CI so sandbox setup warnings fail the run instead of producing a partial BOM.
4. Validate against the schema.
cyclonedx validate --input-file cbom.json --input-version v1_7 --fail-on-errors
cdx-validate -i cbom.json
The first is the CycloneDX CLI; the second is cdxgen's validator, which adds benchmark checks. Schema validation catches bad enum values and fields that do not exist in the declared version. It cannot catch a wrong quantum category or a missing algorithm.
5. Query what you have.
# Every crypto asset, by type and name
jq -r '.components[] | select(.type=="cryptographic-asset")
| [.cryptoProperties.assetType, .name] | @tsv' cbom.json
# Algorithms with no post-quantum security category
jq -r '.components[]
| select(.cryptoProperties.algorithmProperties.nistQuantumSecurityLevel == 0)
| [.name, .cryptoProperties.algorithmProperties.primitive] | @tsv' cbom.json
# What each library implements
jq -r '.dependencies[] | select(.provides)
| "\(.ref) implements \(.provides | join(", "))"' cbom.json
# Certificates sorted by expiry
jq -r '.components[] | select(.cryptoProperties.assetType=="certificate")
| [.cryptoProperties.certificateProperties.notValidAfter, .name] | @tsv' cbom.json | sort
6. Run it in CI.
name: cbom
on: [push]
jobs:
cbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- run: npm install -g @cdxgen/cdxgen --ignore-scripts
- run: cdxgen --include-crypto -o cbom.json .
- run: cdx-validate -i cbom.json
- uses: actions/upload-artifact@v4
with:
name: cbom
path: cbom.json
7. Sign it before sharing. A CBOM shows a reader where your weakest crypto is. cdxgen documents cdx-sign and cdx-verify for JSON Signature Format signatures on BOMs.
How a CBOM feeds a post-quantum migration plan
A CBOM migrates nothing. It turns "where do we use quantum vulnerable public key crypto" from a survey into a query.
- Find exposed primitives. Filter algorithms with
nistQuantumSecurityLevel0 and aprimitiveofkey-agree,pke,signatureorkem. Symmetric ciphers and hashes are a separate discussion; the guide puts AES-128-GCM at category 1. - Separate implemented from used. Walk
dependsOnedges. A library that implements RSA is not a migration item; an application whose protocol uses RSA is. - Attach owners and lifetimes. Each used algorithm leads through the graph to an application and a team. Certificates and keys carry their own dates; long lived material comes first.
- Check the library can move. If the crypto library version in use does not
providesthe target algorithm, the first step is a library upgrade, which is ordinary dependency work. - Model hybrids explicitly. CycloneDX models hybrids with the
combinerprimitive and dependencies on both halves; the guide's example combines ML-KEM-1024 with ECDH on secp521r1. A target state fororders-apicould add the fragment below, which validates against 1.7 when merged into the full BOM above.
{
"components": [
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/ml-kem-768",
"name": "ML-KEM-768",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "kem",
"algorithmFamily": "ML-KEM",
"parameterSetIdentifier": "768",
"cryptoFunctions": ["keygen", "encapsulate", "decapsulate"],
"nistQuantumSecurityLevel": 3
}
}
},
{
"type": "cryptographic-asset",
"bom-ref": "crypto/algorithm/x25519mlkem768",
"name": "X25519MLKEM768",
"cryptoProperties": {
"assetType": "algorithm",
"algorithmProperties": {
"primitive": "combiner",
"cryptoFunctions": ["keygen", "keyderive"]
}
}
}
],
"dependencies": [
{
"ref": "crypto/algorithm/x25519mlkem768",
"dependsOn": ["crypto/algorithm/x25519", "crypto/algorithm/ml-kem-768"]
}
]
}
A cdxgen trace records a negotiated hybrid group as its two halves, so a traced CBOM and a hand written target will not have identical shapes. Normalise before you diff.
- Check policy and certification.
certificationLevelrecords FIPS 140 and Common Criteria levels where only certified modules are allowed. The guide uses NSA's CNSA 2.0 as an example of a machine checkable policy: it describes national security systems supporting and preferring CNSA 2.0 algorithms for software and firmware signing by 2025 and using them exclusively by 2030, with LMS and XMSS advised. Both are registry families, so a CBOM can show whether they are present. - Regenerate and diff. Run the same generators every release. The plan is done when the step 1 query returns nothing for systems in scope and stays that way.
For the organisational side, see Start a cryptographic inventory this week, What does quantum readiness mean?, Why PQC migration needs a CBOM and our CBOM guide.
What a CBOM cannot see
- Runtime negotiated cipher suites. TLS and SSH agree suites at handshake time. A static CBOM shows what code or config allows; a trace shows what was agreed during that run with those peers, nothing more.
- Configuration outside the scan. Crypto policy often sits in system config or load balancers. The guide pairs CBOM with an operations BOM for this reason.
- HSM and KMS internals. A CBOM can say a key is
securedByan HSM with its size, state and algorithm. It cannot see how the HSM implements that algorithm or what else it holds. - Third party services. A trace can record the protocol negotiated with a hosted API. The provider's internal crypto is theirs to disclose.
- Unexercised code and unsupported languages. Tracing records what ran. cdxgen's source level algorithm inventory covers JavaScript and TypeScript; elsewhere crypto may appear only as a library.
- Correct numbers. Security levels are producer supplied. Spot check them.
CycloneDX compositions let a producer mark parts of a BOM as incomplete or unknown, which beats silence.
Where Safeguard fits, honestly
Safeguard does not generate CBOMs, does not build a cryptographic inventory, and does not read cryptoProperties to rank quantum risk. For that job, use the open source tools above.
The fit is one layer down. Safeguard's SBOM generation and analysis is generally available and produces SPDX and CycloneDX SBOMs, with continuous scanning on push, on a schedule or on release. Crypto libraries appear there as ordinary components, so you can see which projects ship a given crypto library version and match it against vulnerability databases. When step 4 of a migration says "upgrade the crypto library first," that is dependency work, where generally available scanning, policies and gates, and autonomous remediation (fix pull requests, switched off by default) apply.
Common mistakes
Treating provides as dependsOn. A library implementing MD5 does not mean your application uses MD5. Query dependsOn for usage.
Putting secrets in value. The schema allows a value for related crypto material. For private keys, secret keys, passwords and tokens, never fill it; record an id that points to your KMS or vault.
Declaring 1.6 while writing 1.7 fields. algorithmFamily, ellipticCurve, tlsGroups and the certificate lifecycle fields are 1.7 only. The document fails validation, and a lenient consumer may silently drop them.
Family names as variant names. A component named AES with no parameter set or mode cannot be assessed. Use the registry pattern (AES-128-GCM) and fill the fields.
Guessed quantum levels. Category 1 written for RSA is worse than no value. Check a sample.
Unstable bom-refs. New UUIDs on every run make every diff show everything removed and re-added.
Ignoring deprecations. Producers should write the 1.7 fields; consumers should read old and new.
Sharing a CBOM like an SBOM. It can show where your weakest crypto is and which keys lack hardware protection. Decide who sees it, keep it separate if needed and link it with BOM-Link.
Trusting a trace as complete, or stopping at the inventory. A clean trace of your tests says nothing about code they skip, and an inventory without owners, dates and a regenerate and diff loop goes stale within a release or two.
How a CBOM relates to NIST guidance
Neither NIST SP 800-218 (the SSDF, February 2022) nor SP 800-161r1 (supply chain risk management, May 2022 with updates as of 1 November 2024) names CBOM, but both frame it. SSDF practice PS.3.2 asks producers to collect, protect, maintain and share provenance data for every component of each release, with an SBOM as the example; a CBOM extends that data to crypto. SSDF practice group PW.4 says reuse is "particularly important for software that implements security functionality," naming cryptographic modules and protocols; provides edges and certificationLevel show which modules you reuse and whether they are certified. SP 800-161r1 frames supply chain risk around limited visibility into how acquired technology is built, and asking suppliers for a CBOM alongside an SBOM is one way to get that visibility for crypto.
FAQ
What is a CBOM in CycloneDX?
A CycloneDX BOM that includes cryptographic-asset components, each with a cryptoProperties object. There is no separate CBOM schema; the crypto model has been part of CycloneDX since 1.6.
What are the four cryptographic asset types in a CBOM?
algorithm, certificate, protocol and related-crypto-material, with the matching properties objects algorithmProperties, certificateProperties, protocolProperties and relatedCryptoMaterialProperties.
Which CycloneDX version should I use for a CBOM?
1.7 for new work. Use 1.6 only for a consumer that cannot read 1.7, and then avoid the 1.7 only fields.
What does nistQuantumSecurityLevel 0 mean?
The schema says 0 means none of NIST's post-quantum security categories is met. RSA, ECDH and similar classical public key algorithms carry 0 in the CBOM guide's examples.
What is the difference between provides and dependsOn in a CBOM?
provides says a component implements something, such as a library implementing an algorithm. dependsOn says a component uses something. Implementing does not imply use.
How do I generate a CBOM for a Java or Node.js project?
With cdxgen: cbom -t java -o cbom.json . for Java keystores and certificates, or cdxgen --include-crypto for JavaScript and TypeScript source. Add a tracebom run to capture what a real run negotiates.
How do I validate a CBOM?
Validate against the schema for the version you declare, for example cyclonedx validate --input-file cbom.json --input-version v1_7 --fail-on-errors. That checks structure and enums, not completeness or correctness.
Should the CBOM be part of my SBOM or a separate file?
Either. The CBOM guide supports both and suggests a separate CBOM when you want different access controls, linked to the SBOM with BOM-Link.
Does Safeguard generate CBOMs?
No. Safeguard generates and analyses SPDX and CycloneDX SBOMs (generally available), where crypto libraries appear as components, but it does not produce CBOMs or cryptographic inventories.
Fix it without waiting for upstream
A CBOM tells you which library implements the crypto you need to change, but the change itself usually ships as an ordinary dependency upgrade: a newer crypto library, a framework release that supports the new algorithm, or a rebuilt container image. The fit here is indirect, since none of the steps below read a CBOM, but they are how the library side of a crypto migration and its security fixes actually reach production.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
None of these demos generate a CBOM. They show the dependency side of the work: finding and upgrading the libraries that implement your crypto.
The first demo is a real Safeguard CLI session. It installs the CLI, opens the interactive terminal and asks it to fix a lodash CVE: the assistant reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, and pushes nothing. The same flow applies when your CBOM shows a crypto library version too old to implement the algorithm you are moving to.
Click through it at your own pace, or open it full screen.
The second demo sets up the Safeguard runner on your own machine, approves it with its device code, and then scans from the terminal. Run it next to cdxgen in the same pipeline: cdxgen writes the CBOM, and Safeguard scans the dependencies that implement what the CBOM lists.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Once connected, you can ask which of your projects contain a given crypto library and version, the question step 4 of a migration plan raises for every library a CBOM names.
Click through it at your own pace, or open it full screen.
To try the CLI yourself, download Safeguard and follow the CLI docs.
Quick check
A crypto library in your CBOM lists RSA under provides, but nothing lists RSA under dependsOn. Is RSA a migration item?
Not on this evidence. provides means the library implements RSA, and the schema says that does not imply it is in use. Confirm with a trace or source analysis before planning work.
Your CBOM declares specVersion 1.6 and uses algorithmFamily and ellipticCurve. What happens?
It fails schema validation, because those fields were added in CycloneDX 1.7. Declare 1.7, or fall back to the 1.6 fields (the variant name and the deprecated curve string).
Sources
- CycloneDX: Cryptography Bill of Materials (CBOM) capability page
- OWASP CycloneDX Authoritative Guide to CBOM, second edition, 21 October 2025 (PDF)
- CycloneDX specification: bom-1.7.schema.json
- CycloneDX specification: bom-1.6.schema.json
- CycloneDX specification: bom-1.5.schema.json
- CycloneDX specification: cryptography-defs.schema.json
- CycloneDX specification: cryptography-defs.json registry data
- CycloneDX specification releases
- Ecma International: ECMA-424, CycloneDX Bill of materials specification, 2nd edition
- cdxgen README
- cdxgen CLI documentation
- cdxgen tracebom guide
- @cdxgen/cdxgen on npm
- CycloneDX CLI README (validate command)
- NIST SP 800-218, Secure Software Development Framework
- NIST SP 800-218 full text (PDF)
- NIST SP 800-161r1, Cybersecurity Supply Chain Risk Management Practices
Last reviewed: 23 October 2026. CycloneDX schemas and cdxgen change often; check the linked sources for the latest versions.