Skip to main content

CycloneDX Application Analysis

Sonatype Lifecycle analysis supports the CycloneDX standard, the industry’s most advanced software bill of materials (SBOM) format.

An SBOM is a list of parts (packages and libraries) included in the application. Just as a manufacturing bill of materials includes all sub-assemblies, the SBOM also includes the direct and transitive dependencies along with any internal components made by your organization.

Analyzing an SBOM

Any Sonatype scanner and most of the integrations will analyze SBOMs found in the root context of the application scan target when using the naming format listed below in the Identification Source section.

SBOMs may be targeted directly using the command line scanner (CLI), by uploading to the user interface, or by scripting using the Third-Party Scan REST API.

Any application scan may be exported as an SBOM in the CycloneDX and SPDX formats. Learn about more SBOM use cases from our SBOM guide.

CycloneDX provides many native application scanners on its repository. Find a complete list at the CycloneDX Tool Center.

Identification Source

The CycloneDX format is used as an identification source in the Application Composition Report. The prefix of the file name is used as the source. Third Party is used as the identification source when no source is provided through the API or using the filename prefix.

  • bom.xml

  • <source>-bom.xml

  • <source>-bom.json

  • <public app id>_<version>_<timestamp>.cdx.<json|xml>

Sonatype scanners use the above naming formats to identify and analyze SBOMs within archives. Make sure your SBOM names follow this format when outputting them through third-party tools.

Component Identifiers, Package-URL, and SHA-1 Hash

For libraries declared in the SBOM, Lifecycle uses the following priority when identifying components. An example of each is included below. When a component is found more than once in the sbom, only the data of the first component will be processed/shown. Hashes included in the exported CycloneDX report will consist of a truncated (first 20 digits) SHA-1 rather than the full hash.

  1. Package-URL (PURL)

  2. SHA-1 Hashes

  3. Component Identifiers (group/scope/namespace, name, version)

Dependency Relationships

The CycloneDX 1.4+ format includes dependency graph information on the direct and transitive relationships between dependencies. The Lifecycle scanners include this information in the scan report and for the application dependency tree.

Components at the first level of listed dependencies in the SBOM are identified during an analysis. SBOMs with nested components will pass validation; however, nested components are not supported and are ignored during the analysis.

See the Dependency Graph below.

Innersource Components

CycloneDX can be used to identify Innersource producers as well as when they are consumed by other applications as dependencies. Similarly, this can be used to identify proprietary components. When processing the report, Lifecycle will use the identity information provided in the CycloneDX file when the component is unknown; greatly reducing the number of component unknown violations. This would include in the report any security and license data provided in the SBOM.

See the examples of a producer and consumer below.

Sonatype properties in SBOMs

Software Bill of Materials generated by Sonatype includes Sonatype-specific metadata under the Sonatype namespace taxonomy.

Property

Description

sonatype:identification_sources

The source of the identity information for the component. This is either sonatype or some other source typically from the original bill of materials.

sonatype:match_state

Verify when the comparison of a component to known components is or is not a match in one of the following ways: exact, similar, or unknown

sonatype:match_filenames

The filename where the identified component is found

sonatype:truncated_sha1

An internal identifier used by Sonatype made from the first 20 chars of either the component's sha1 hash or a synthetic hash of the component's coordinates.

Application Reports

In conjunction with using CycloneDX to do the application analysis, you can also export any application report in Lifecycle to the CycloneDX format.

Vulnerability Analysis Section

The CycloneDX 1.4+ format includes analysis information of the vulnerabilities. Sonatype imports the vulnerability analysis found in this section to include in the scan report.

The Sonatype Data Services team frequently evaluates vulnerabilities that enter our systems for accuracy and repeatability. They may determine a vulnerability is not applicable and therefore do not report the vulnerability against the component in our products. For these reasons, we favor reporting data coming from Sonatype Data Services over content reported from third-party sources to reduce the noise reported to development teams and used for enforcement.

  • The SBOM uses our vulnerability data for every known component in the Sonatype Data Services. Imported vulnerability data is not included.

  • For components not found in the Sonatype Data Services, the vulnerability and license details are sourced from the originally imported SBOM.

Custom Vulnerability Information

You may add vulnerability information to the SBOM using the Vulnerability Analysis Details REST API.

<?xml version="1.0" encoding="UTF-8"?>
<bom serialNumber="urn:uuid:cb3c8aae-d8a0-4ef5-a40d-de537161f948" version="1" xmlns="http://cyclonedx.org/schema/bom/1.6">
  <metadata>
    <timestamp>2023-01-12T14:46:58Z</timestamp>
    <component type="application" bom-ref="pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom">
      <group>org.example</group>
      <name>ACME-Test</name>
      <version>1.0-SNAPSHOT</version>
      <purl>pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom</purl>
    </component>
  </metadata>
  <components>
    <component type="library" bom-ref="pkg:maven/javax.inject/javax.inject@1?type=jar">
      <group>javax.inject</group>
      <name>javax.inject</name>
      <version>1</version>
      <hashes>
        <hash alg="SHA-1">6975da39a7040257bd51d21a231b76c915872d38</hash>
      </hashes>
      <licenses>
        <license>
          <id>Apache-2.0</id>
        </license>
      </licenses>
      <purl>pkg:maven/javax.inject/javax.inject@1?type=jar</purl>
    </component>
    <component type="library" bom-ref="pkg:maven/commons-io/commons-io@2.6?type=jar">
      <group>commons-io</group>
      <name>commons-io</name>
      <version>2.6</version>
      <licenses>
        <license>
          <id>Apache-2.0</id>
        </license>
      </licenses>
      <purl>pkg:maven/commons-io/commons-io@2.6?type=jar</purl>
      <modified>false</modified>
    </component>
    <component type="library" bom-ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar">
      <group>com.fasterxml.jackson.core</group>
      <name>jackson-databind</name>
      <version>2.13.4</version>
      <hashes>
        <hash alg="SHA-1">98b0edfa8e4084078f10b7b356c300ded4a71491</hash>
      </hashes>
      <licenses>
        <license>
          <id>Apache-2.0</id>
        </license>
      </licenses>
      <purl>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar</purl>
    </component>
    <component type="library" bom-ref="pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar">
      <group>org.example</group>
      <name>ACME-data</name>
      <version>1.0-SNAPSHOT</version>
      <purl>pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar</purl>
    </component>
  </components>
  <dependencies>
    <dependency ref="pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom">
      <dependency ref="pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar"/>
      <dependency ref="pkg:maven/commons-io/commons-io@2.6?type=jar"/>
    </dependency>
    <dependency ref="pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar">
      <dependency ref="pkg:maven/javax.inject/javax.inject@1?type=jar"/>
      <dependency ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar"/>
      <dependency ref="pkg:maven/commons-io/commons-io@2.6?type=jar"/>
    </dependency>
    <dependency ref="pkg:maven/javax.inject/javax.inject@1?type=jar"/>
    <dependency ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar"/>
    <dependency ref="pkg:maven/commons-io/commons-io@2.6?type=jar"/>
  </dependencies>
  <vulnerabilities>
    <vulnerability>
      <id>CVE-2022-42003</id>
      <source>
        <name>NVD</name>
        <url>http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-42003</url>
      </source>
      <ratings>
        <rating>
          <source>
            <name>NVD</name>
          </source>
          <score>7.5</score>
          <severity>critical</severity>
          <method>CVSSv3</method>
          <vector>CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H</vector>
        </rating>
      </ratings>
      <cwes>
        <cwe>502</cwe>
      </cwes>
      <analysis>
        <state>resolved_with_pedigree</state>
        <justification>requires_environment</justification>
        <responses>
          <response>workaround_available</response>
          <response>update</response>
        </responses>
        <detail>Analysis Detail</detail>
      </analysis>
      <affects>
        <target>
          <ref>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar</ref>
        </target>
      </affects>
    </vulnerability>
  </vulnerabilities>
</bom>
{
  "bomFormat" : "CycloneDX",
  "specVersion" : "1.6",
  "serialNumber" : "urn:uuid:d069c08a-1e5b-4de2-b6d7-509964190ea7",
  "version" : 1,
  "metadata" : {
    "component" : {
      "group" : "org.example",
      "name" : "ACME-Test",
      "version" : "1.0-SNAPSHOT",
      "licenses" : [ ],
      "purl" : "pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom",
      "type" : "library",
      "bom-ref" : "pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom"
    }
  },
  "components" : [
    {
      "publisher" : "The Apache Software Foundation",
      "group" : "commons-io",
      "name" : "commons-io",
      "version" : "2.6",
      "hashes" : [
        {
          "alg" : "SHA-1",
          "content" : "815893df5f31da2ece4040fe0a12fd44b577afaf"
        }
      ],
      "licenses" : [
        {
          "license" : {
            "id" : "Apache-2.0"
          }
        }
      ],
      "purl" : "pkg:maven/commons-io/commons-io@2.6?type=jar",
      "type" : "library",
      "bom-ref" : "pkg:maven/commons-io/commons-io@2.6?type=jar"
    },
    {
      "group" : "org.example",
      "name" : "ACME-data",
      "version" : "1.0-SNAPSHOT",
      "licenses" : [ ],
      "purl" : "pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar",
      "type" : "library",
      "bom-ref" : "pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar"
    },
    {
      "group" : "javax.inject",
      "name" : "javax.inject",
      "version" : "1",
      "description" : "The javax.inject API",
      "hashes" : [
        {
          "alg" : "SHA-1",
          "content" : "6975da39a7040257bd51d21a231b76c915872d38"
        }
      ],
      "licenses" : [
        {
          "license" : {
            "id" : "Apache-2.0"
          }
        }
      ],
      "purl" : "pkg:maven/javax.inject/javax.inject@1?type=jar",
      "type" : "library",
      "bom-ref" : "pkg:maven/javax.inject/javax.inject@1?type=jar"
    },
    {
      "publisher" : "FasterXML",
      "group" : "com.fasterxml.jackson.core",
      "name" : "jackson-databind",
      "version" : "2.13.4",
      "hashes" : [
        {
          "alg" : "SHA-1",
          "content" : "98b0edfa8e4084078f10b7b356c300ded4a71491"
        }
      ],
      "licenses" : [
        {
          "license" : {
            "id" : "Apache-2.0"
          }
        }
      ],
      "purl" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar",
      "type" : "library",
      "bom-ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar"
    }
  ],
  "dependencies" : [
    {
      "ref" : "pkg:maven/org.example/ACME-Test@1.0-SNAPSHOT?type=pom",
      "dependsOn" : [
        "pkg:maven/commons-io/commons-io@2.6?type=jar",
        "pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar"
      ]
    },
    {
      "ref" : "pkg:maven/commons-io/commons-io@2.6?type=jar",
      "dependsOn" : [ ]
    },
    {
      "ref" : "pkg:maven/org.example/ACME-data@1.0-SNAPSHOT?type=jar",
      "dependsOn" : [
        "pkg:maven/javax.inject/javax.inject@1?type=jar",
        "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar",
        "pkg:maven/commons-io/commons-io@2.6?type=jar"
      ]
    },
    {
      "ref" : "pkg:maven/javax.inject/javax.inject@1?type=jar",
      "dependsOn" : [ ]
    },
    {
      "ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar",
      "dependsOn" : [ ]
    }
  ],
  "vulnerabilities": [
      {
          "id": "CVE-2022-42003",
          "source": {
              "name": "NVD",
              "url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-42003"
           },
          "ratings": [
              {
                  "source": {
                      "name": "NVD"
                  },
                  "score": 7.5,
                  "severity": "critical",
                  "method": "CVSSv3",
                  "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
              }
          ],
          "cwes": [
              502
          ],
          "analysis": {
            "state": "resolved_with_pedigree",
            "justification": "requires_environment",
            "response": [
                    "workaround_available",
                    "update"
                ],
            "detail": "Analysis Detail"
          },
          "affects": [
              {
                  "ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar"
              }
          ]
      }
  ]
}

dependency-bom.xml

<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" version="1">
  <metadata>    
    <component type="application" bom-ref="acme-app">
      <name>Acme Application</name>
      <version>9.1.1</version>
      <purl>pkg:maven/org.acme/acme-app@9.1.1?type=jar</purl>
    </component>
  </metadata>
  <components>
    <component type="framework" bom-ref="pkg:maven/org.acme/web-framework@1.0.0?type=jar">
      <group>org.acme</group>
      <name>web-framework</name>
      <version>1.0.0</version>
      <purl>pkg:maven/org.acme/web-framework@1.0.0?type=jar</purl>
    </component>
    <component type="library" bom-ref="pkg:maven/org.acme/persistence@3.1.0?type=jar">
      <group>org.acme</group>
      <name>persistence</name>
      <version>3.1.0</version>
      <purl>pkg:maven/org.acme/persistence@3.1.0?type=jar</purl>
    </component>
    <component type="library" bom-ref="pkg:maven/org.acme/common-util@3.0.0?type=jar">
      <group>org.acme</group>
      <name>common-util</name>
      <version>3.0.0</version>
      <purl>pkg:maven/org.acme/common-util@3.0.0?type=jar</purl>
    </component>
  </components>
  <dependencies>
    <dependency ref="acme-app">
      <dependency ref="pkg:maven/org.acme/web-framework@1.0.0?type=jar"/>
      <dependency ref="pkg:maven/org.acme/persistence@3.1.0?type=jar"/>
    </dependency>
    <dependency ref="pkg:maven/org.acme/web-framework@1.0.0?type=jar">
      <dependency ref="pkg:maven/org.acme/common-util@3.0.0?type=jar"/>
    </dependency>
    <dependency ref="pkg:maven/org.acme/persistence@3.1.0?type=jar">
      <dependency ref="pkg:maven/org.acme/common-util@3.0.0?type=jar"/>
    </dependency>
    <dependency ref="pkg:maven/org.acme/common-util@3.0.0?type=jar"/>
  </dependencies>
</bom>

producer-bom.xml

<?xml version="1.0" encoding="UTF-8"?>
<bom version="1" xmlns="http://cyclonedx.org/schema/bom/1.6">
  <metadata>
    <component type="application" bom-ref="pkg:generic/producer-component@1.0.0">
      <name>producer-component</name>
      <version>1.0.0</version>
    </component>
  </metadata>
  <components>
    <component type="library" bom-ref="pkg:generic/some-awesome-component@1.0">
      <name>some-awesome-component</name>
      <version>1.0</version>
      <purl>pkg:generic/some-awesome-component@1.0</purl>
    </component>
  </components>
  <dependencies>
    <dependency ref="pkg:generic/producer-component@1.0.0">
      <dependency ref="pkg:generic/some-awesome-component@1.0" />
    </dependency>
    <dependency ref="pkg:generic/some-awesome-component@1.0" />
  </dependencies>
</bom>

consumer-bom.xml

<?xml version="1.0" encoding="UTF-8"?>
<bom version="1" xmlns="http://cyclonedx.org/schema/bom/1.6">
  <metadata>
    <component type="application" bom-ref="pkg:npm/consumer@1.0.0">
      <name>consumer</name>
      <version>1.0.0</version>
    </component>
  </metadata>
  <components>
    <component type="library" bom-ref="pkg:npm/producer@1.0">
      <name>producer</name>
      <version>1.0</version>
      <purl>pkg:npm/producer@1.0</purl>
    </component>
    <component type="library" bom-ref="pkg:npm/some-awesome-component@1.0">
      <name>some-awesome-component</name>

Analyze using the CycloneDX maven plugin

The CycloneDX maven plugin may be used to generate an SBOM to include when analyzing your application. Following is a sample request to make the BOM and set the name of the bom using the outputName.

mvn org.cyclonedx:cyclonedx-maven-plugin:2.8.2:makeAggregateBom -DoutputName=cyclonedx-bom

This will generate cyclonedx-bom.xml and cyclonedx-bom.json which are compatible with the Lifecycle scanners.

The CycloneDX output may be included directly in the project pom.xml to be picked up by the Lifecycle Analysis automatically.

This example includes the CycloneDX generation in the pom.xml plugins. Note the outputName is used in the project.artifactId to generate the name of the BOM file.

<plugin>
  <groupId>org.cyclonedx</groupId>
  <artifactId>cyclonedx-maven-plugin</artifactId>
  <version>2.8.2</version>
  <configuration>
    <projectType>library</projectType>
    <schemaVersion>1.5</schemaVersion>
    <includeBomSerialNumber>true</includeBomSerialNumber>
    <includeCompileScope>true</includeCompileScope>
    <includeProvidedScope>true</includeProvidedScope>
    <includeRuntimeScope>true</includeRuntimeScope>
    <includeSystemScope>true</includeSystemScope>
    <includeTestScope>false</includeTestScope>
    <includeLicenseText>false</includeLicenseText>
    <outputReactorProjects>true</outputReactorProjects>
    <outputFormat>all</outputFormat>
    <outputName>${project.artifactId}-bom</outputName>
    <outputDirectory>${project.build.directory}</outputDirectory>
    <verbose>false</verbose>
  </configuration>
</plugin>

Learn more from the CycloneDX maven plugin documentation.

Analyze using the Jenkins plugin

By default, the Jenkins plugin will not evaluate the bom.xml. A custom scan target is needed.

nexusPolicyEvaluation 
  iqApplication: 'SampApp', 
  iqScanPatterns: [
    [scanPattern: '**/bom.xml'], 
    [scanPattern: '**/*-bom.xml']
  ], 
  iqStage: 'build'

More at Jenkins - Lifecycle

Analyze using the Bamboo plugin

Bamboo Scan Targets control what files are examined. To evaluate CycloneDX, add bom.xml to the scan targets via a comma-separated list e.g.

Example Bamboo Scan Patterns

**/bom.xml,**/*-bom.xml

To find more information on how to configure Bamboo please go to Bamboo Data Center.