Overview

This is the fourth part of our SBOM compliance series. In the previous post, we discussed BSI TR-03183-2 v1.1, Germany’s SBOM compliance framework, and how to validate your SBOM using sbomqs. In this post, we will discuss BSI TR-03183-2 v2.0, the updated version released in September 2024, what changed, what it now expects from an SBOM, and how to check compliance. Let’s go.

Context

đŸ‡©đŸ‡Ș Germany’s Federal Office for Information Security (BSI) released version 2.0.0 of TR-03183-2 on 2024-09-20. This is a significant update, not just a clarification pass. v2.0 adds new required fields, introduces a brand new optional tier, tightens the language around vulnerability information.

If you’ve aligned your SBOM tooling with BSI v1.1, you have to read this carefully, as the number of fields increases.

And the motivation remains the same: the EU Cyber Resilience Act (CRA). BSI TR-03183-2 is the technical guideline that defines exactly what an SBOM must contain to satisfy CRA requirements. v2.0 brings it closer to the practical realities of modern software supply chains, covering compiled code, interpreted scripts, archives, and deployable artifacts more precisely.

BSI’s Definition of SBOM

Before we look at the fields, let’s understand how BSI itself defines an SBOM. This matters because the definition shapes every requirement that follows.

BSI §3.1 defines it as:

“A ‘Software Bill of Materials’ (SBOM) is a machine-processable file containing supply chain relationships and details of the components used in a software product. It supports automated processing of information on these components. This covers both the so-called ‘primary component’ and used (e.g. external/third-party) components.”

A few things to understand here:

Machine-processable, not just machine-readable. BSI is deliberate about this distinction. “Machine-processable” means tooling can create, read, modify, analyse, and act on SBOM data. “Machine-readable” is intentionally avoided, it’s a weaker guarantee.

Supply chain relationships, not just a list. An SBOM isn’t a flat inventory. It describes relationships b/w components, including who depends on what. BSI v2.0 explicitly adds: “It describes any relationship of the covered components.” This underpins the recursive dependency requirement.

SBOM MUST NOT contain vulnerability information. This is one of the clearest tightenings from v1.1 to v2.0. The v1.1 says an SBOM “does not contain” vulnerability data, whereas v2.0 says it MUST NOT, and adds:

“Still, a document containing both SBOM and vulnerability information does not conform to this Technical Guideline.”

SBOM data is static. Vulnerability data is dynamic. Mixing them into one file causes the static SBOM to be unnecessarily regenerated every time vulnerability information is updated. BSI recommends CSAF or VEX for distributing vulnerability information separately.

One SBOM per software version. A new SBOM must be generated for each software version. An updated SBOM for the same version is required only when component data is corrected or added, not for every vulnerability update.

What makes BSI v2.0 different from v1.1?

If you’ve followed Part 3 of compliance series(BSI:v1.1), here’s what changed:

Three-tier field system. v1.1 had two tiers: Required and Additional, whereas v2.0 adds a third tier:

  • Required: fields that MUST always be present. No exceptions.
  • Additional: fields that MUST be included if the data exists and prerequisites are met.
  • Optional: fields that MAY be included if they exist. No obligation either way.

Four new required component fields. v2.0 requires every component to declare:

  • Its filename (actual filename, not path)
  • Its executable property (is it executable or non-executable?)
  • Its archive property (is it an archive or not?)
  • Its structured property (does it retain metadata about its contents?)

These fields exist because BSI v2.0 is precise about what a “component” actually is. Compiled binaries, Python scripts, .zip packages, container images, they all have different properties, and an SBOM must now declare those explicitly.

Hash algorithm changed. v1.1 required SHA-256, whereas v2.0 now requires SHA-512 for the deployable component hash. And the field is renamed from “Hash value of the executable component” to “Hash value of the deployable component”.

New licence fields. v2.0 introduces a more precise licence model:

  • Associated licences (required): The licences under which the component can be used by the licensee.
  • Concluded licences (additional): The licence the SBOM creator has concluded applies to this component.
  • Declared licences (optional): The licence the original component creator declared.

CycloneDX minimum version bumped. v1.1 required CycloneDX 1.4+, whereas v2.0 requires CycloneDX 1.5+. SPDX minimum is now 2.2.1+ (was 2.3+).

Transitional system. v2.0 introduces a 6-month grace period: after BSI publishes a new version, the previous version MAY still be used for up to six months. After that, the previous version must not be applied.

Note: BSI v2.0 was designed with SPDX 3.0 in mind. Several of its fields have no direct equivalent in SPDX 2.3, so gaps in the SPDX mappings below are expected, not oversights. If you are working with SPDX 2.3 today, BSI v1.1 is the version aligned to it. BSI v2.0 is the precursor to v2.1, where SPDX 3.0 becomes a hard requirement.

Now, let’s walk through each field.

Required Fields

BSI §5.2 defines required fields at two levels: for the SBOM document itself, and for each component.

SBOM-Level Required Fields

1. Creator of the SBOM

Official definition:

“Email address of the entity that created the SBOM. If no email address is available this MUST be a ‘Uniform Resource Locator (URL)’, e.g. the creator’s home page or the project’s web page.”

The is identical to v1.1: a machine-actionable contact point so automated tooling can reach the responsible party without human intervention. v2.0 adds explicit examples of acceptable URLs (creator’s home page or project web page), making it clearer what a fallback URL should look like.

Accepted values: valid email (preferred), valid URL (fallback only).

SBOM Mapping:

  • SPDX:

    • creationInfo.creator (Person or Organization entry, email extracted)
  • CycloneDX:

    • metadata.authors[].email
    • metadata.manufacturer.email or metadata.manufacturer.url
    • metadata.supplier.email or metadata.supplier.url

NOTE: Any one of these sources satisfying the email/URL requirement is sufficient.

2. Timestamp

Official definition:

“Date and time of the SBOM data compilation according to the specification of the formats (see section 4)”

Same as v1.1.

Accepted values: RFC 3339 / ISO 8601 compliant timestamp (e.g., 2025-04-25T00:42:27Z).

SBOM Mapping:

  • SPDX:

    • creationInfo.created
  • CycloneDX:

    • metadata.timestamp

Component-Level Required Fields

3. Component Creator

Official definition:

“Email address of the entity that created and, if applicable, maintains the respective component. If no email address is available this MUST be a ‘Uniform Resource Locator (URL)’, e.g. the creator’s home page or the project’s web page.”

Same rationale as the SBOM creator, applied at the component level. If a CVE is found in a library, automated tooling needs to contact that library’s maintainer, not a human intermediary.

Accepted values: valid email (preferred), valid URL (fallback only).

SBOM Mapping:

  • SPDX:

    • PackageOriginator (email preferred)
    • PackageSupplier (fallback)
  • CycloneDX:

    • components[].authors[].email
    • components[].manufacturer.email or components[].manufacturer.url
    • components[].supplier.email or components[].supplier.url

4. Component Name

Official definition:

“Name assigned to the component by its creator. If no name is assigned this MUST be the actual filename.”

v2.0 adds a fallback: if no name is assigned by the creator, the SBOM MUST use the actual filename. This is new, v1.1 had no fallback.

SBOM Mapping:

  • SPDX:

    • PackageName
  • CycloneDX:

    • components[].name

5. Component Version

Official definition:

“Identifier used by the creator to specify changes in the component to a previously created version. Identifiers according to Semantic Versioning or alternatively Calendar Versioning SHOULD be used if one determines the versioning scheme. Existing identifiers MUST NOT be changed for this purpose. If no version is assigned this MUST be the creation date of the file expressed as full-date according to RFC 3339 section 5.6.”

v2.0 again adds a fallback: if no version exists, use the file’s creation date in RFC 3339 full-date format (e.g., 2024-09-20). This handles components with no formal versioning.

SBOM Mapping:

  • SPDX:

    • PackageVersion
  • CycloneDX:

    • components[].version

6. Filename of the Component(New in v2.0)

Official definition:

“The actual filename of the component (i.e. not its path); see also section 3.2.1”

This is entirely new in v2.0. The filename is the actual file on disk, for example, libssl.so.3 or requests-2.31.0-py3-none-any.whl. The path is excluded; only the filename itself is required.

Why? Because BSI v2.0 defines a “component” as a single executable or archive file. The filename ties the SBOM entry to the exact file that was analyzed or delivered. It makes the SBOM directly verifiable against the actual artifacts on a system.

SBOM Mapping:

  • SPDX:

    • No dedicated native field. May be expressed via ExternalRef or PackageName when the filename is the name.
  • CycloneDX:

    • components[].name (when set to the actual filename)

7. Dependencies on Other Components

Official definition:

“Enumeration of all components on which this component is directly dependent, according to requirements in section 5.1, or which this component contains according to requirements in section 3.2.1.”

v2.0 extends this: dependencies now also include components that are contained within this component. Not just what it depends on at runtime, but what it physically contains.

The dependency section must exist in the SBOM, and the primary component must explicitly declare its dependencies. Every dependency relationship must reference a component that is itself defined within the SBOM. Dependencies must be recursively resolved on each path downward from the primary component, continuing at least until the first component that falls outside the scope of delivery

NOTE: Leaf components with no dependencies are compliant by declaring an empty dependency list.

SBOM Mapping:

  • SPDX:

    • Relationships of type DEPENDS_ON or CONTAINS
  • CycloneDX:

    • dependencies[]: ref (the component) and dependsOn (its direct dependencies)

8. Associated Licences

Official definition:

“Associated licence(s) of the component from the perspective of the SBOM creator. For specifics see sections 6.1 and 8.1.9.”

This was called “Licence” in v1.1. The rename to “Associated licences” reflects a more precise licensing model in v2.0. Associated licences are the licences under which the component can actually be used by the licensee, which may differ from what the original creator declared.

Accepted values: SPDX identifier (e.g., MIT, Apache-2.0), SPDX expression, or LicenseRef-* for non-SPDX licences. NONE, NOASSERTION, and free-text names are not accepted.

SBOM Mapping:

  • SPDX:

    • PackageLicenseConcluded (preferred)
    • PackageLicenseDeclared (fallback)
  • CycloneDX:

    • components[].licenses[].license.id
    • components[].licenses[].expression

9. Hash Value of the Deployable Component(Updated in v2.0)

Official definition:

“Cryptographically secure checksum (hash value) of the deployed component (i.e. as a file on a mass storage device) as SHA-512; see also section 3.2.1”

Two changes from v1.1:

  • Renamed: “executable component” => “deployable component”. This intentionally broadens the scope to include archives, packages, and container images that are deployed but not directly “executed.”
  • Algorithm changed: SHA-256 => SHA-512. SHA-512 provides a stronger hash for supply chain integrity verification.

SHA-512 only. MD5, SHA-1, SHA-256, and all other algorithms do not satisfy this requirement.

SBOM Mapping:

  • SPDX:

    • PackageChecksum with algorithm SHA512
  • CycloneDX:

    • externalReferences[type=distribution or distribution-intake].hashes[] with alg = SHA-512

10. Executable Property(New in v2.0)

Official definition:

“Describes whether the component is executable; possible values are ’executable’ and ’non-executable’; see also section 8.1.3”

Executable files are files whose code is executed by a computer, either directly (compiled binaries) or via a runtime (Python scripts, Shell scripts, Java bytecode, shared libraries). Configuration files, graphic files, and documentation are NOT executable.

This property allows downstream tooling to immediately know whether a component is code that runs, which is directly relevant to vulnerability impact analysis.

Accepted values: executable or non-executable.

SBOM Mapping:

  • SPDX:

    • No dedicated native field. May be expressed via ExternalRef with category OTHER.
  • CycloneDX:

    • components[].properties[] with name bsi:component:executable and value true or false

11. Archive Property(New in v2.0)

Official definition:

“Describes whether the component is an archive; possible values are ‘archive’ and ’no archive’; see also section 8.1.4”

An archive is a combination of multiple components, like a .zip, .tar, .jar, or container image. Note that an archive can also be an executable file (e.g., a self-extracting executable). Compression of an archive does not change this property.

Accepted values: archive or no archive.

SBOM Mapping:

  • SPDX:

    • No dedicated native field. May be expressed via ExternalRef with category OTHER.
  • CycloneDX:

    • components[].properties[] with name bsi:component:archive and value true or false

12. Structured Property(New in v2.0)

Official definition:

“Describes whether the component is a structured file, i.e. metadata of the contents is still present (see section 3.2.1); possible values are ‘structured’ and ‘unstructured’; see also section 8.1.5. If a component contains both structured and unstructured parts the value ‘structured’ MUST be used.”

A structured archive retains metadata about its original components, containers, packages, .zip, .tar, .tar.gz, .7z are structured. An unstructured archive (like a firmware image or raw binary blob) does not retain that metadata.

Accepted values: structured or unstructured.

SBOM Mapping:

  • SPDX:

    • No dedicated native field. May be expressed via ExternalRef with category OTHER.
  • CycloneDX:

    • components[].properties[] with name bsi:component:structured and value true or false

Additional Fields

Additional fields MUST be provided if they exist and their prerequisites are fulfilled (BSI §5.3). If the data exists, omitting it is non-compliant.

SBOM-Level Additional Fields

13. SBOM-URI

Official definition:

“Uniform Resource Identifier (URI)” of this SBOM

Unchanged from v1.1. A URI uniquely identifies the SBOM document itself, enabling cross-referencing, retrieval, and linking to VEX documents or updated SBOMs.

SBOM Mapping:

  • SPDX:

    • documentNamespace
  • CycloneDX:

    • serialNumber combined with version

Component-Level Additional Fields

14. Source Code URI

Official definition:

“Uniform Resource Identifier (URI)” of the source code of the component, e.g. the URL of the utilised source code version in its repository, or if a version cannot be specified the utilised source code repository itself."

Enables downstream consumers to audit source code, verify licence compliance, and locate patches when a vulnerability is discovered.

SBOM Mapping:

  • SPDX:

    • ExternalRef with category OTHER (no dedicated native field)
  • CycloneDX:

    • components[].externalReferences[] with type vcs (preferred) or source-distribution

15. URI of the Deployable Form of the Component(Renamed in v2.0)

Official definition:

“Uniform Resource Identifier (URI)”, which points directly to the deployable (e.g. downloadable) form of the component."

Renamed from “URI of the executable form” to “URI of the deployable form”, consistent with the hash renaming. It now covers any distributable artifact, not just executables.

SBOM Mapping:

  • SPDX:

    • PackageDownloadLocation
  • CycloneDX:

    • components[].externalReferences[] with type distribution or distribution-intake

16. Other Unique Identifiers

Official definition:

“Other identifiers that can be used to identify the component or to look it up in relevant databases, such as Common Platform Enumeration (CPE) or Package URL (purl).”

Unchanged from v1.1. PURL and CPE enable automated cross-referencing against vulnerability databases.

Accepted values:

  • PURL (e.g., pkg:npm/lodash@4.17.21)
  • CPE (e.g., cpe:2.3:a:lodash:lodash:4.17.21:*:*:*:*:*:*:*)

SBOM Mapping:

  • SPDX:

    • ExternalRef with category PACKAGE-MANAGER, type purl
    • ExternalRef with category SECURITY, type cpe22Type or cpe23Type
  • CycloneDX:

    • components[].purl
    • components[].cpe

17. Concluded Licences(New in v2.0)

Official definition:

“The licence(s) that the licensee of the component has concluded for this component. For specifics see sections 6.1 and 8.1.9.”

This is a new licence concept in v2.0. Concluded licences are the licences that the SBOM creator (as the licensee of this component) has concluded actually apply, after reviewing the declared licences, the source code, and making a licensing determination. It may differ from what the component creator originally declared.

SBOM Mapping:

  • SPDX:

    • PackageLicenseConcluded
  • CycloneDX:

    • components[].licenses[].license.id with appropriate identifier

Optional Fields

This is an entirely new tier introduced in v2.0 (§5.4). Optional fields MAY be included if the data exists, there is no obligation either way. This is the key distinction from Additional fields: even if the data exists, omitting Optional fields is not a compliance violation.

Component-Level Optional Fields

18. Declared Licences(New in v2.0)

Official definition:

“The licence(s) that the licensor of the component has declared for this component. For specifics see sections 6.1 and 8.1.9.”

The licence as declared by the original component creator. Think of it as the “upstream” licence claim. As an optional field, it provides additional transparency into the licensing chain without being mandatory.

SBOM Mapping:

  • SPDX:

    • PackageLicenseDeclared
  • CycloneDX:

    • components[].licenses[].license.id (declared variant)

19. Hash Value of the Source Code(Moved from Additional to Optional)

Official definition:

“Cryptographically secure checksum (hash value) of the component source code. A specific algorithm how to create a hash value of multiple source files or a source code tree, and which hash algorithm is utilised for that has not yet been determined.”

In v1.1, this was an Additional field (MUST provide if available). v2.0 demotes it to Optional (MAY provide). The reason is honest: BSI has not yet standardized the algorithm for hashing a multi-file source tree. Until that is resolved, it cannot be a mandatory data point.

SBOM Mapping:

  • SPDX:

    • PackageVerificationCode (closest available SPDX field)
  • CycloneDX:

    • components[].externalReferences[] with type vcs or source-distribution, including associated hashes[]

Field Summary Table

#FieldLevelCategoryBSI Section
1Creator of the SBOMSBOMRequired§5.2.1
2TimestampSBOMRequired§5.2.1
3Component creatorComponentRequired§5.2.2
4Component nameComponentRequired§5.2.2
5Component versionComponentRequired§5.2.2
6Filename of the componentComponentRequired§5.2.2
7Dependencies on other componentsComponentRequired§5.2.2
8Associated licencesComponentRequired§5.2.2
9Hash value of the deployable componentComponentRequired§5.2.2
10Executable propertyComponentRequired§5.2.2
11Archive propertyComponentRequired§5.2.2
12Structured propertyComponentRequired§5.2.2
13SBOM-URISBOMAdditional§5.3.1
14Source code URIComponentAdditional§5.3.2
15URI of the deployable formComponentAdditional§5.3.2
16Other unique identifiersComponentAdditional§5.3.2
17Concluded licencesComponentAdditional§5.3.2
18Declared licencesComponentOptional§5.4.1
19Hash value of source codeComponentOptional§5.4.1

v1.1 had 13 fields. v2.0 has 19. Required fields alone grew from 8 to 12.

How to evaluate your SBOM against BSI TR-03183-2 v2.0

At this point, we’ve looked at all 19 fields. The next natural question is:

How do you actually check whether your SBOM meets BSI v2.0 requirements?

This is where sbomqs comes in.

sbomqs is an open-source CLI tool that evaluates SBOMs after they are generated. It checks both SBOM quality and compliance against standard frameworks, including BSI TR-03183-2 v2.0.

For a broader look at how sbomqs scoring works across BSI v1.1 and v2.0, see our earlier post on sbomqs BSI scoring support.

Run a single command to score your SBOM against BSI v2.0:

sbomqs score --profile bsi-v2.0 your-sbom.cdx.json

And the o/p looks like this:

SBOM Quality Score: 9.4/10.0	 Grade: A	Components: 2 	 EngineVersion: 6	File: testdata/bsi/cdx/validFullyCompliantBsiV21.cdx16.json


+---------------------+--------------------------+------------------------+--------------------------------+
|       PROFILE       |         FEATURE          |         STATUS         |              DESC              |
+---------------------+--------------------------+------------------------+--------------------------------+
| BSI TR-03183-2 v2.0 | sbom_spec_version        | 10.0/10.0              | CycloneDX 1.6 meets minimum    |
|                     |                          |                        | version 1.5                    |
+                     +--------------------------+------------------------+--------------------------------+
|                     | sbom_creator             | 10.0/10.0              | SBOM creator contact(email)    |
|                     |                          |                        | provided via authors           |
+                     +--------------------------+------------------------+--------------------------------+
|                     | sbom_timestamp           | 10.0/10.0              | SBOM creation timestamp is     |
|                     |                          |                        | valid and RFC3339-compliant.   |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_creator             | 10.0/10.0              | creator contact (email or URL) |
|                     |                          |                        | declared for all components    |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_name                | 10.0/10.0              | component name declared for    |
|                     |                          |                        | all components                 |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_version             | 10.0/10.0              | component version declared for |
|                     |                          |                        | all components                 |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_filename            | 10.0/10.0              | filename declared for all      |
|                     |                          |                        | components                     |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_depth               | 10.0/10.0              | Dependencies are recursively   |
|                     |                          |                        | declared and structurally      |
|                     |                          |                        | complete.                      |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_associated_license  | 10.0/10.0              | licence information declared   |
|                     |                          |                        | for all components             |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_hash                | 0.0/10.0               | no components declare a        |
|                     |                          |                        | SHA-512 deployable hash.       |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_executable_property | 10.0/10.0              | executable property declared   |
|                     |                          |                        | for all components             |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_archive_property    | 10.0/10.0              | archive property declared for  |
|                     |                          |                        | all components                 |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_structured_property | 10.0/10.0              | structured property declared   |
|                     |                          |                        | for all components             |
+                     +--------------------------+------------------------+--------------------------------+
|                     | sbom_uri                 | 10.0/10.0 (additional) | SBOM-URI is declared.          |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_source_code_url     | 10.0/10.0 (additional) | Source code URI declared for   |
|                     |                          |                        | all components.                |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_download_url        | 10.0/10.0 (additional) | Executable URI declared for    |
|                     |                          |                        | all components.                |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_other_identifiers   | 10.0/10.0 (additional) | Unique identifiers declared    |
|                     |                          |                        | for all components.            |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_concluded_license   | 10.0/10.0 (additional) | concluded licence declared for |
|                     |                          |                        | all components                 |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_declared_license    | 10.0/10.0 (optional)   | declared licence declared for  |
|                     |                          |                        | all components                 |
+                     +--------------------------+------------------------+--------------------------------+
|                     | comp_source_hash         | 10.0/10.0 (optional)   | source hash declared for all   |
|                     |                          |                        | components.                    |
+---------------------+--------------------------+------------------------+--------------------------------+


Summary:
Required Fields   : 12/13 compliant
Additional Fields : 5/5 compliant
Optional Fields   : 2/2 present

Love to hear your feedback https://forms.gle/anFSspwrk7uSfD7Q6

The o/p gives you three clear sections now:

  • Required fields (12 checks): mapped to BSI §5.2, creator, timestamp, component identity, filename, dependencies, licences, deployable hash, and the three new property flags.
  • Additional fields (5 checks, marked additional): mapped to BSI §5.3, SBOM-URI, source code URI, deployable URI, unique identifiers, and concluded licences.
  • Optional fields (2 checks, marked optional): declared licences and source code hash. These are reported as “present” rather than “compliant” since they are never a compliance violation to omit.

The (additional) and (optional) labels in the STATUS column make the three tiers immediately distinguishable. For most real-world SBOMs, the biggest gaps will appear in the new required fields: filename, executable property, archive property, and structured property are rarely populated by standard SBOM generators today.

Conclusion and what’s next

In this post, we discussed BSI TR-03183-2 v2.0, the September 2024 update to Germany’s SBOM compliance framework. We started with how BSI defines an SBOM itself: a machine-processable file focused on supply chain relationships, with a hard prohibition on including vulnerability data.

We looked at what sets v2.0 apart from v1.1: a third optional field tier, four new required component fields (filename, executable, archive, and structured properties), a hash algorithm upgrade to SHA-512, a rename from “executable” to “deployable” throughout, and a more precise licensing model with three distinct licence concepts.

We walked through all 19 fields across all three tiers: what BSI officially requires, why each field exists, and how it maps to SPDX and CycloneDX. And we saw how sbomqs evaluates your SBOM against BSI v2.0 with a single command.

If you are building software products targeting the EU market, v2.0 is the standard to align with today. The 6-month transitional period means the clock is already ticking from the day a newer version is published.

In the next post of this series, we’ll look at BSI TR-03183-2 v2.1, latest version of BSI.

Resources