Software Bills of Material (SBOMs) are documents which contain a list of components and dependencies of a given software ecosystem, like a list of ingredients in a recipe. On its own, an SBOM can provide some context to how the application was created, what kinds of functionality it may contain, as well as provide a glimpse into the lifecycle of the software project.
When a team includes VEX (Vulnerability Exploitability eXchange) in an SBOM, they are better able to view context for vulnerabilities in the stack, accelerate remediation prioritization, and even make compliance more efficient through automation.
VEX is an extension of the CycloneDX SBOM standard which includes more security-related context for the components listed. In addition to the software component version and licensing information, VEX includes fields about the vulnerability, as well as fields for the security team to justify an exemption to the vulnerability, and finally a way to show the planned actions for remediation.
The current status of the vulnerability according to the SBOM publisher. The status field can be quickly scanned for immediate information about a particular vulnerability.
Here are the status field’s possible values and a short description of each:
The justification field allows a team to provide additional context to the status field’s value. This is especially useful when a team marks a vulnerability as not_affected to provide the reasoning for why this vulnerability does not affect the software ecosystem.
Here are the possible values for the justification field and a short description of each:
Adding VEX to a software product’s SBOM adds the context of real-world impact to vulnerabilities discovered in the stack, reducing the noise and allowing for more streamlined prioritization, and adds clarity to stakeholder communications.
There are many advantages to using VEX, for example:
Using an intentionally vulnerable open source software project to practice creating, updating, and packaging a VEX-formatted SBOM can provide some insight into how an organization can utilize VEX to communicate better with their stakeholders.
In our example, we will be using the NodeJS app called BrokenCrystals, which is an intentionally vulnerable open source project for learning Application Security.
First, clone the BrokenCrystals repository from Github to a local directory:
git clone https://github.com/NeuraLegion/brokencrystals.git
Next, we need to install the package’s dependencies:
cd brokencrystals
npm install
Now, we generate an SBOM using the built-in npm tool, using the CycloneDX format, and exporting to a file named `sbom.json`:
npm sbom --sbom-format cyclonedx > sbom.json
With this SBOM in hand, we are now ready to add our VEX data to it.
In order to add our VEX information into our SBOM, we will need a tool for creating and updating the files. Vexctl is a simple utility which allows you to add VEX entries for a given package.
In our example, we use go to install vexctl. Additional methods of installation are available and are described in the Github README.
install vexctl (assuming you have go environment):
go install github.com/openvex/vexctl@latest
alternatively, you can directly install the binary from the releases page (https://github.com/openvex/vexctl/releases)
Now that we have our tool installed, we can take a look at a vulnerability which exists in the SBOM. With the package libxmljs, we find that the version included in BrokenCrystals (1.0.11) is vulnerable to CVE-2024-34392, a type confusion vulnerability which can lead to denial of service and remote code execution.
Since we know that we are not using the vulnerable method in our installation of BrokenCrystals, we can create a VEX entry which reflects that information:
vexctl create --product="pkg:npm/libxmljs@1.0.11" \
--vuln="CVE-2024-34392" \
--status="not_affected" \
--justification="vulnerable_code_not_present"
The output of this command is a VEX statement:
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://openvex.dev/docs/public/vex-fc7aa4d2618d658c2dbbaf3e09cb11dee3786efad6a9de4c8c13b6672a6e25f2",
"author": "Unknown Author",
"timestamp": "2025-02-11T09:53:27.082143077-05:00",
"version": 1,
"statements": [
{
"vulnerability": {
"name": "CVE-2024-34392"
},
"timestamp": "2025-02-11T09:53:27.08214467-05:00",
"products": [
{
"@id": "pkg:npm/libxmljs@1.0.11"
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_present"
}
]
}
Save this output to a text file named vex.json.
Using another utility, we can combine the VEX statement with the CycloneDX SBOM, to create an enhanced SBOM that provides the downstream consumers with more specific information about the vulnerable components of the system.
Install the CycloneDX Editor/Validator project to enhance working with the CycloneDX SBOM:
python -m pip install cyclonedx-editor-validator
Once the utility is installed, we can issue the command to combine the VEX statement from vexctl, and the generated CycloneDX SBOM:
cdx-ev merge-vex –-output-file enhanced-sbom.json sbom.json vex.json
The resulting enhanced-sbom.json file contains both the full CycloneDX SBOM generated at the beginning of this tutorial as well as the VEX statement we created to provide downstream maintainers up-to-date information about the vulnerable status of the system.
Whether one wants to provide customers or other maintainers with more transparency, adding VEX statements to the SBOMs of software projects enhances the component data found within and presents an opportunity to communicate more clearly and openly with downstream consumers of the software ecosystem.