Safeguard
Supply Chain Security•

CBOM Field by Field: CycloneDX Crypto Assets and How to Generate One

A CycloneDX CBOM records algorithms, certificates, protocols and keys as cryptographic-asset components. Every field explained, plus how to generate one.

Safeguard Security Team
32 min read

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-asset components, kept inside your SBOM or shipped as its own document.
  • Each crypto asset has one required property, assetType: algorithm, certificate, protocol or related-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.
  • provides means a library implements something. dependsOn means 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 relatedCryptographicAssets link, 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.

DateReleaseWhat changed for CBOM
26 June 2023CycloneDX 1.5No crypto support; the 1.5 schema has no cryptographic-asset type
9 April 2024CycloneDX 1.6Adds cryptographic-asset, cryptoProperties with four asset types, and provides dependencies. CBOM guide first edition.
21 October 2025CycloneDX 1.7Adds 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 2025ECMA-424 second editionEcma's standard defines CycloneDX 1.7, including "domain-specific modelling for cryptographic artefacts"
24 February 2026Cryptography registrylastUpdated value in cryptography-defs.json at the time of writing
2 June and 17 September 2026CycloneDX 1.7.1 and 1.7.2Patch 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 valueProperties objectUse it forExample names
algorithmalgorithmPropertiesA specific algorithm variant with parametersAES-128-GCM, SHA-256, ML-KEM-768
certificatecertificatePropertiesA certificate your software ships, loads or presentsa server certificate, an internal CA root
protocolprotocolPropertiesA protocol and version with its suites or transformsTLS 1.3, SSH, IKEv2, QUIC
related-crypto-materialrelatedCryptoMaterialPropertiesKeys, tokens, nonces, salts, passwords, signaturesa 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

FieldTypeValues or meaning
primitiveenumdrbg, mac, block-cipher, stream-cipher, signature, hash, pke, xof, kdf, key-agree, kem, ae, combiner, key-wrap (new in 1.7), other, unknown
algorithmFamilyenum (1.7)One of 93 registry families, such as AES, SHA-2, ECDH, ECDSA, RSASSA-PSS, ML-KEM, ML-DSA, SLH-DSA, LMS, XMSS
parameterSetIdentifierstring128 in AES-128, 256 in SHA-256, SHA2-128s in SLH-DSA
ellipticCurveenum (1.7)One of 246 registry curves as namespace/name, such as nist/P-256 or other/Curve25519
curvestringDeprecated in 1.7
executionEnvironmentenumsoftware-plain-ram, software-encrypted-ram, software-tee, hardware, other, unknown
implementationPlatformenumgeneric, x86_32, x86_64, ARM v7, v8 and v9 profiles, s390x, ppc64, ppc64le, other, unknown
certificationLevelarray of enumnone, FIPS 140-1, 140-2 and 140-3 levels 1 to 4, Common Criteria EAL1 to EAL7 with plus variants, other, unknown
modeenumcbc, ecb, ccm, gcm, cfb, ofb, ctr, other, unknown
paddingenumpkcs5, pkcs7, pkcs1v15, oaep, raw, other, unknown
cryptoFunctionsarray of enumgenerate, keygen, encrypt, decrypt, digest, tag, keyderive, sign, verify, encapsulate, decapsulate, other, unknown
classicalSecurityLevelintegerClassical security in bits
nistQuantumSecurityLevelintegerNIST 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:

FieldPurpose
serialNumberCA assigned serial number (1.7)
subjectName, issuerNameDistinguished names
notValidBefore, notValidAfterISO 8601 validity window
certificateFormat, certificateFileExtensionFor example X.509 and crt; the file extension field replaces certificateExtension
fingerprintHash of the certificate excluding its signature (1.7)
certificateStateLifecycle states pre-activation, active, suspended, deactivated, revoked, destroyed, with optional reason, or a custom state (1.7)
creationDate, activationDate, deactivationDate, revocationDate, destructionDateLifecycle timestamps (1.7)
certificateExtensionsTen common extensions by name (basicConstraints, keyUsage, extendedKeyUsage, subjectAlternativeName and others) with a value, or custom extensions (1.7)
relatedCryptographicAssetsLinks 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 of tls, ssh, ipsec, ike, sstp, wpa, dtls, quic, eap-aka, eap-aka-prime, prins, 5g-aka, other, unknown. Version 1.6 stopped at wpa.
  • version: a string such as 1.3.
  • cipherSuites: each suite has a name, algorithms (bom-refs to algorithm assets), identifiers (code points such as 0x13, 0x01), and in 1.7 tlsGroups and tlsSignatureSchemes.
  • ikev2TransformTypes: the RFC 7296 transform types (encr, prf, integ, ke) plus esn and auth. In 1.7 each is an array of small objects, such as an encryption entry with name, keyLength and an algorithm reference.
  • relatedCryptographicAssets: replaces the deprecated cryptoRefArray.

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

FieldValues or meaning
typeprivate-key, public-key, secret-key, key, ciphertext, signature, digest, initialization-vector, nonce, seed, salt, shared-secret, tag, additional-data, password, credential, token, other, unknown
idYour identifier, such as a KMS key ID
statepre-activation, active, suspended, deactivated, compromised, destroyed, which the schema ties to NIST SP 800-57 key states
creationDate, activationDate, updateDate, expirationDateLifecycle timestamps
valueThe material's value (see Common mistakes)
size, formatSize in bits; format such as PEM, DER, P8
securedBymechanism (schema examples: HSM, TPM, SGX, Software, None) and optional algorithmRef
fingerprint, relatedCryptographicAssetsNew 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 fieldIn 1.7Use instead
algorithmProperties.curveDeprecatedellipticCurve (registry enum)
(none)NewalgorithmFamily (registry enum)
certificateProperties.signatureAlgorithmRef, subjectPublicKeyRefDeprecatedrelatedCryptographicAssets
certificateProperties.certificateExtensionDeprecatedcertificateFileExtension
relatedCryptoMaterialProperties.algorithmRefDeprecatedrelatedCryptographicAssets
protocolProperties.cryptoRefArrayDeprecatedrelatedCryptographicAssets
IKEv2 transform reference arraysDeprecated formArrays 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.

EdgeWritten asRead as
Application to librarydependsOnThe app links or loads this library
Library to algorithm or protocolprovidesThe library contains an implementation
Application or protocol to algorithmdependsOnThis 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/x25519 makes diffs far easier.
  • Both edge types. The library provides five assets; the application and protocol dependsOn what is in use. If the library also implemented SHA-1, it would appear under provides only.
  • 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. securedBy set to Software is 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 cbom command 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 the os project type and points you to obom.
  • Source derived algorithms. For JavaScript and TypeScript, cdxgen follows constants through common node:crypto, WebCrypto and JWT call sites. In the cdxi shell, .cryptos lists all crypto assets and .sourcecryptos only 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-crypto adds crypto to ordinary generation. The cryptographic-asset type needs spec 1.6 or newer and is pruned if you downgrade output.
  • The tracebom command 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 as X25519MLKEM768 is recorded as its two halves, x25519 and ml-kem-768. Loaded crypto libraries get a cdx:dynamic:cryptoLibrary property.

Static versus traced generation

ApproachWhat it seesWhat it missescdxgen entry point
Static source analysisAlgorithms and parameters at call sites in supported languagesAlgorithms chosen at runtime or by a peer; unsupported languagescbom or cdxgen --include-crypto
Keystore and certificate parsingCertificates and keys in files the scan can readKeys in HSMs or remote KMS; certificates fetched at runtimecbom -t java, container and rootfs scans
Runtime tracingTLS version, suites and groups negotiated during the run; libraries loadedCode paths and peers the run did not touchtracebom --trace-crypto
Hand authoringAnything you know, such as HSM backed keys or a vendor's stated configurationAnything you forget; drifts as code changesAn 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.

  1. Find exposed primitives. Filter algorithms with nistQuantumSecurityLevel 0 and a primitive of key-agree, pke, signature or kem. Symmetric ciphers and hashes are a separate discussion; the guide puts AES-128-GCM at category 1.
  2. Separate implemented from used. Walk dependsOn edges. A library that implements RSA is not a migration item; an application whose protocol uses RSA is.
  3. 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.
  4. Check the library can move. If the crypto library version in use does not provides the target algorithm, the first step is a library upgrade, which is ordinary dependency work.
  5. Model hybrids explicitly. CycloneDX models hybrids with the combiner primitive and dependencies on both halves; the guide's example combines ML-KEM-1024 with ECDH on secp521r1. A target state for orders-api could 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.

  1. Check policy and certification. certificationLevel records 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.
  2. 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 securedBy an 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 situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull 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

Last reviewed: 23 October 2026. CycloneDX schemas and cdxgen change often; check the linked sources for the latest versions.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.