A Software Bill-of-Materials (SBOM) is a document to share information about the software used, dependencies, and essentially what the software is made of. SBOMs have many different use cases, and some examples include checking license compliance, dependencies for vulnerabilities using databases such as CVE and OSV, among others.
Erlang/OTP has multiple third-party dependencies. Some are vendored into the source code of Erlang/OTP:
- pcre (
erts/emulator/pcre) - zlib (
erts/emulator/zlib) - asmjit (
erts/emulator/asmjit) - openssl (
erts/emulator/openssl) - zstd (
erts/emulator/zstd) - others
The Erlang/OTP project provides source SBOMs starting with OTP 28. Below we detail the steps necessary to run yourself the generation of the Erlang/OTP source SBOM.
For information about the structure of the source SBOM, please follow Software Bill-of-Materials (SBOM)).
Erlang/OTP provides a source SBOM in each release. Here we provide details of how to generate yourself an Erlang/OTP source SBOM.
The simplest way to generate a source SBOM for Erlang/OTP is to use oss-review-toolkit (ORT)
with the configuration files found in this repo (.ort/config/config.yml and .ort.yml).
.ort/config/config.ymlcontains configuration information towards ORT, e.g., configuration of the scanner to use, advisor, etc..ort.ymlcontains configuration information for this specific project, e.g., which files to exclude from scanner, curation of licenses, etc.
To run ORT locally, we detail the steps running ORT from source and from Docker.
Tip
In cases where one needs to test the .github/scripts/otp-compliance.es script,
it is useful to download scan-result.json from any pull request in Erlang/OTP.
This file can be found in Save ORT Scanner cache step inside the Create SBOM Github task.
The scanning phase may take 2 h to run locally.
By downloading a recent scan, one can run generation of the SPDX report immediately,
and test the results running .github/scripts/otp-compliance.es sbom otp-info --sbom-file ort/cli/bom.spdx.json --input-file ort/cli/scan-result.json.
-
Install
oss-review-toolkit(ORT) andscancode. -
Run the ORT analyzer (some paths may need tweaking depending on where you are):
./gradlew cli:run --args="-c .ort/config/config.yml analyze -i . -o . -f JSON --repository-configuration-file=.ort.yml" -
Run the ORT scanner (
scancodeis needed):./gradlew cli:run --args="-c .ort/config/config.yml scan -o . -f JSON -i analyzer-result.json" -
Generate ORT SPDX report
./gradlew cli:run --args="report -i cli/scan-result.json -o . -f SpdxDocument -O SpdxDocument=outputFileFormats=JSON" -
From the Erlang/OTP repo, run the following escript to fix some known issues from the generated SPDX:
.github/scripts/otp-compliance.es sbom otp-info --sbom-file ort/cli/bom.spdx.json --input-file ort/cli/scan-result.json
-
Run the ORT analyzer (some paths may need tweaking depending on where you are) and choose an appropriate version, in this example
51.0.0:docker run -v $(PWD):/sbom ghcr.io/oss-review-toolkit/ort:51.0.0 -c .ort/config/config.yml analyze -i . -o . -f JSON --repository-configuration-file=.ort.yml
-
Run the ORT scanner:
docker run -v $(PWD):/sbom ghcr.io/oss-review-toolkit/ort:51.0.0 -c .ort/config/config.yml scan -o . -f JSON -i analyzer-result.json
-
Generate ORT SPDX report
docker run -v $(PWD):/sbom ghcr.io/oss-review-toolkit/ort:51.0.0 report -i cli/scan-result.json -o . -f SpdxDocument -O SpdxDocument=outputFileFormats=JSON
-
From the Erlang/OTP repo, run the following escript to fix some known issues from the generated SPDX, and to separate Erlang/OTP applications into their own SPDX Packages:
.github/scripts/otp-compliance.es sbom otp-info --sbom-file ort/cli/bom.spdx.json --input-file ort/cli/scan-result.json
Erlang/OTP generates and uploads to sigstore the generated SBOM via Github Actions.
All the details can be found in otp/.github/workflows/main.yaml.
The generated source SBOM should be verified. The current escript contains some basic
verification capabilities and that be complemented by other tools, such as ntia-conformance-checker.
To verify that the SBOM is correct, run the following escript after [Steps From Source] or [Steps From Docker]:
.github/scripts/otp-compliance.es sbom test-file --sbom-file otp.spdx.jsonDetails for how to update Erlang/OTP applications and vendor dependencies follow.
NOTE: The source SBOM that you are generating will be based on the current
Erlang version that runs otp-compliance.es. This is simply because the version of
some dependencies cannot be known beforehand.
The escript otp-compliance.es detects Erlang/OTP applications using a simple
heuristic. Anything that contains an .app.src will be place in its own SPDX
Package. To detect the correct version for each Erlang application, you must ensure that
application:get_all_key(AppName) can run without issues.
For example, one cannot expect wx application to work if the system was not
build with the required dependencies.
Updating the description of the .app.src package and re-building the SBOM will
make the new description to be placed in the generated source SBOM.
If there is a new Erlang/OTP release, the system that runs otp-compliance.es
must be the one that contains the new version.
Any new Erlang/OTP application must simply contain a .app.src file to
be placed as a new SPDX Package. Failing to do so will still add the files making
up the new application, but these files will not be part of their own SPDX Package.
Delete the code and any remaining .app.src files. Make sure that the application was
not part of a dependency in other .app.src files.
Re-run the source SBOM generation steps ([Erlang/OTP source SBOM]).
Vendor packages are identified by a JSON vendor.info file that contains fields to identify the vendor dependency.
Each vendor.info file will implicitly generate a SPDX Package (within the source SBOM) to separate vendor libraries from Erlang/OTP applications.
This file may be a list of JSON objects. For simplicity, we document the fields using a JSON object.
[
{
"ID": "erts-asmjit",
"description": "Asmjit library",
"copyrightText": "Copyright (c) 2008-2023 The AsmJit Authors",
"downloadLocation": "https://github.com/asmjit/asmjit",
"homepage": "https://github.com/asmjit/asmjit",
"licenseDeclared": "Zlib",
"name": "asmjit",
"versionInfo": "029075b84bf0161a761beb63e6eda519a29020db",
"sha": "029075b84bf0161a761beb63e6eda519a29020db",
"path": "./erts/emulator/asmjit",
"exclude": ["./erts/emulator/asmjit/vendor.info"],
"supplier": "Person: Petr Kobalicek",
"purl": "pkg:github/asmjit/asmjit",
"sha": "029075b84bf0161a761beb63e6eda519a29020db",
"update": "./erts/emulator/asmjit/update.sh"
}
]Fields summary:
ID: represents theidof the third party using the following format:<SPDX-TOP-LEVEL-PACKAGE>-<VENDOR-ID>. In the SPDX generation,SPDX-TOP-LEVEL-PACKAGEindicates the SPDX Package under which this vendor is a part of. For example, we writeerts-asmjitfor the vendor libraryasmjitthat is a part of theertsSPDX Package. Top-level packages are: -erts- All Erlang apps, e.g.,stdlib,ssl,common_test, etc. - If you are unsure about the name of theSPDX-TOP-LEVEL-PACKAGE, take a look at the source SBOM to identify packages (under keypackagesin the SBOM).description: a brief description of what this vendor library does.copyrightText: copyright text associated with the top-level package/library/3pp using SPDX License Identifiers.downloadLocation: URI of the vendor library to download. If using Github, use preferablyhttps//rather thangit+https//or similars. This is because the download location is used for vulnerability scanning in.github/scripts/otp-compliance.es.homepage: homepage of the vendor library.licenseDeclared: license as declared by the vendor, following a SPDX license identifier.name: name of the library.versionInfo: version of the library/project/3pp. In case of no version number being available, write the commit sha.sha: sha commit forversionInfo, they need to be updated together!ecosystem: List of valid ecosystems in OSV Ecosystems where this value is omitted for C/C++ code (e.g.,asmjit,pcre2,zlib,zstd, etc), and used invendor.jsonforjquery.path: path to the vendor library inside Erlang/OTP. This can point to a folder or a list of files.- Folder: any file inside the folder is considered part of the vendor library (e.g., asmjit vendor.info).
- List of files: only the files listed here are part of a vendor library (e.g., erts-config vendor.info).
exclude: excludes the listed files or directories from what is listed inpath. That is, they will not included into the generated SPDX package, but will instead be part of the SPDX package which this package is part of.comment: any comment.supplier: supplier of the software, following this standard:Person: <person name> (<email>), whereemailis optional.Organization: <Organization name> (email), whereemailis optional.NOASSERTION, where the person adding this information (you) could not reach a reasonable conclusion, the person adding this information made no attempt to determine this field, or this field was left with no information and no meaning should be implied by doing so.
purl: if the vendor has a specificpurl, we choose this format. Otherwise, we follow the guidelines from the PURL Specification.update: the path to a script to be used to update the dependency. This script is called by renovate when a new version of a dependency is found.
To update the package, perform any modifications in a vendor.info package
and re-run the source SBOM generation steps ([Erlang/OTP source SBOM]).
If the vendor package is optional, the create_vendor_relations() function in the .github/scripts/otp-compliance.es script needs to be updated to add the OPTIONAL_COMPONENT_OF relation for the package.
For vendor packages in erts, erlang:system_info(embedded_3pps) (erts/emulator/beam/erl_bif_info.c) also needs to be updated. The 3pp should be part of either the value for the included key (the build includes the 3pp) or the excluded key (the build does not include the 3pp). If the package is optional, the build should automatically place it as part of the value of the correct key.
Follow the same steps as in [Update SPDX Vendor Packages]. When running the SBOM generator, make sure to check that the new vendor dependency exists in its own package.
The renovate.json5 file also needs to be updated
to make sure that the new vendored dependency gets updated as it should.
Delete the code and any remaining vendor.info files.
Re-run the source SBOM generation steps ([Erlang/OTP source SBOM]).
Delete the proper sections in renovate.json5.
VEX files allow to communicate which vulnerabilities are false positives and which ones are actual vulnerabilities. VEX files are important to explicitly state that some vendor dependencies are (not) vulnerabilities in your software.
Erlang/OTP has chosen to communicate VEX information using the OpenVEX implementation.
Install vexctl, which is written in Go.
An easy way to install go on Ubuntu is to type the following:
sudo snap install go --classicand add to your PATH the snap apps (e.g., to your .bashrc),
export PATH=$PATH:/snap/binAlternatively, install Go from source or binaries.
Automatic
go install github.com/openvex/vexctl@latest
From source
Download and install vextctl as follows
git clone https://github.com/openvex/vexctl.git
cd vexctl
makeAdd to your path the binary,
export PATH=$PATH:<your-path-to-vexctl>/vexctl/Erlang/OTP will maintain VEX files for the latests three releases.
Because of this, Erlang/OTP will always contain the latest information in the master branch.
Any OpenVEX file in other branches is considered outdated.
The OpenVEX files are located in vex/otp-26.openvex.json, vex/otp-27.openvex.json, and vex/otp-28.openvex.json (e.g.). These files are generated from the make/openvex.table and the script .github/scripts/otp-compliance.es.
-
make/openvex.tablecontains all known CVEs on a per release basis, with top-level objects forotp-XXbranches, where eachotp-XXobject has as value a list of dependencies with their CVE and the status.Example:
"otp-28": [ { "pkg:github/openssl/openssl@636dfadc70ce26f2473870570bfd9ec352806b1d" : "CVE-2025-4575", "status": {"not_affected": "vulnerable_code_not_present"} }, { "pkg:github/PCRE2Project/pcre2@2dce7761b1831fd3f82a9c2bd5476259d945da4d": "OSV-2025-300", "status": {"not_affected": "vulnerable_code_not_present"} }, ... ]
The status corresponds to the possible status from the OpenVEX specification.
In case of not_affected, a reason must be provided (similar to the specification).
The make/openvex.table is considered to be an append-only structure, where one should not do modifications to existing data nor removal.
Changes should be done via .github/scripts/otp-compliance.es applied on the openvex.table. The main reason is to use
openvex.table as a simple source of truth without boilerplate, since VEX statements can be long due to the way in which one
must express range versions for a vulnerability.
In the example above, pkg:github/openssl/openssl@636dfadc70ce26f2473870570bfd9ec352806b1d corresponds to
the package URL for the OpenSSL version with commit 636dfadc70ce26f2473870570bfd9ec352806b1d, which corresponds
to the version of OpenSSL used in OTP-X. Starting from OTP 28, this information can be found in the corresponding
vendor.info file for OpenSSL (e.g., /erts/emulator/openssl/vendor.info in the sha field).
The file openvex.table is a subset of fields of the OpenVEX specification.
The format is a JSON object that contains OTP VEX statements. A top-level valid field is the
OTP version key (e.g., otp-29), followed by a list of objects. Each JSON object can have the following structure.
- A key with a Purl, which uniquely identifies the application that the statement talks about, and a CVE string as value.
- A key
statuswith valueStatus :: "affected" | "fixed" | "under_investigation | "not_affected" | Affected, whereAffectedis an object explained below. Affectedis an object that may have the following keysaffectedwith value string that explains mitigation strategiesfixedwith value where the fix was introduced.
Example
Assume the following ficticious case, where we want to report CVE-2023-48795 on OTP 23.
{
"otp-23": [
{
"pkg:otp/ssh@4.10.1": "CVE-2023-48795",
"status":
{ "affected": "Mitigation: If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability"
}
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": { "affected": "Mitigation message, update to the next release"}
}
]
}In all the cases explained below, the running of the tool .github/scripts/otp-compliance.es vex does not commit changes.
One has to execute the output commands to introduce changes.
Code Generation
Erlang/OTP creates releases (e.g., OTP-28) and also divides apps in different versions, which means that one can declare vulnerabilities in multiple ways.
Example, should we mention that the ssh app in OTP-23 is vulnerable or that ssh-4.10.1 which released in OTP-23 is vulnerable, or both?
To help us produce accurate results, Erlang/OTP favours to write the exact application version in which a bug was introduced or detected,
and the exact app version in which the app was fixed, within its OTP release.
For example, if we place in openvex.table:
{
"otp-23": [
{
"pkg:otp/ssh@4.10.1": "CVE-2023-48795",
"status": { "affected": "Mitigation: If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability",
"fixed": ["pkg:otp/ssh@4.11.1.6"]
}
}
]
}and execute the script
.github/scripts/otp-compliance.es vex run -b otp-23 | bashGenerates the following VEX commands
vexctl add --in-place vex/otp-23.openvex.json --product='pkg:otp/erlang@23.1,pkg:otp/erlang@23.1.1,pkg:otp/erlang@23.1.2,pkg:otp/erlang@23.1.3,pkg:otp/erlang@23.1.4,pkg:otp/erlang@23.1.5,pkg:otp/erlang@23.2,pkg:otp/erlang@23.2.1,pkg:otp/erlang@23.2.2,pkg:otp/erlang@23.2.3,pkg:otp/erlang@23.2.4,pkg:otp/erlang@23.2.5,pkg:otp/erlang@23.2.6,pkg:otp/erlang@23.2.7,pkg:otp/erlang@23.3,pkg:otp/erlang@23.3.1,pkg:otp/erlang@23.3.2,pkg:otp/erlang@23.3.3,pkg:otp/erlang@23.3.4,pkg:otp/erlang@23.3.4.1,pkg:otp/erlang@23.3.4.2,pkg:otp/erlang@23.3.4.3,pkg:otp/erlang@23.3.4.4,pkg:otp/erlang@23.3.4.5,pkg:otp/erlang@23.3.4.6,pkg:otp/erlang@23.3.4.7,pkg:otp/erlang@23.3.4.8,pkg:otp/erlang@23.3.4.9,pkg:otp/erlang@23.3.4.10,pkg:otp/erlang@23.3.4.11,pkg:otp/erlang@23.3.4.12,pkg:otp/erlang@23.3.4.13,pkg:otp/erlang@23.3.4.14,pkg:otp/ssh@4.10.1,pkg:otp/ssh@4.10.2,pkg:otp/ssh@4.10.3,pkg:otp/ssh@4.10.4,pkg:otp/ssh@4.10.5,pkg:otp/ssh@4.10.6,pkg:otp/ssh@4.10.7,pkg:otp/ssh@4.10.8,pkg:otp/ssh@4.11,pkg:otp/ssh@4.11.1,pkg:otp/ssh@4.11.1.1,pkg:otp/ssh@4.11.1.2,pkg:otp/ssh@4.11.1.3,pkg:otp/ssh@4.11.1.4,pkg:otp/ssh@4.11.1.5' --vuln='CVE-2023-48795' --status='affected' --action-statement='Mitigation: If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability'
vexctl add --in-place vex/otp-23.openvex.json --product='pkg:otp/erlang@23.3.4.19,pkg:otp/erlang@23.3.4.18,pkg:otp/erlang@23.3.4.17,pkg:otp/erlang@23.3.4.16,pkg:otp/erlang@23.3.4.15,pkg:otp/ssh@4.11.1.6' --vuln='CVE-2023-48795' --status='fixed'The first command in the script has figured out the exact OTP versions that are vulnerable from the range of affected and fixed exact versions,
as well as created the range of ssh applications that are affected by the vulnerability.
The second command simply states which OTP application versions are fixed.
Below we continue with how to initialize and use the tool to report various states, and show examples for Erlang/OTP applications and third party application on which Erlang/OTP builds upon.
This will only be needed once, but if you need to initialize and provide existing known CVEs, you can use .github/scripts/otp-compliance.es.
The first time that we generate OpenVEX statements we call .github/scripts/otp-compliance.es vex init --input-file make/openvex.table -b otp-28. This init script outputs instructions to execute in the shell, which invokes commands from vexctl (Installation steps here). You can run and execute the scripts as follows, .github/scripts/otp-compliance.es vex init --input-file make/openvex.table -b otp-28 | bash (if you use bash).
The script is idempotent, meaning that running consecutive times the script will not change its input.
Because of this, you run this command only for a new OTP release, and for coming CVEs you use .github/scripts/otp-compliance.es vex run ....
This last command will not update the time and assumes that the otp-XX.openvex.json exists (because the init command must be run first).
Example for new Release
To release VEX files for a new release, OTP-29, add the name branch to make/openvex.table (assuming there are known CVEs):
{
"otp-29": []
}
Execute the script to create the VEX statements for OTP-29:
.github/scripts/otp-compliance.es vex init --input-file make/openvex.table -b otp-29There are no known vulnerabilities, so this VEX statement can be published as is.
For vendor CVEs, it may make sense to communicate with the ecosystem that a CVE for vendor X is under investigation.
If it is trivial to know whether we are affected, one could skip reporting under_investigation and add directly the fixed, or vulnerable statements.
To update or insert VEX statements for OTP-29, update the make/openvex.table and run:
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29The script will output commands to run (similar to a dry-run). Once piped to bash, they are executed.
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29 | bash
Add and commit the changes.
Example
make/openvex.table contains:
{
"otp-29": []
}
Lets assume there is FIKA-2026-BROD detected in zlib. We can issue an under_investigation statement updating the make/openvex.table
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
}
]
}Execute the command below to update the OpenVEX statements.
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29 | bashErlang/OTP should not issue an under_investigation unless it is known that it will take some days to understand if Erlang/OTP is vulnerable to a vendor dependency.
If the vulnerability under investigation is a false positive, one can convey this information using OpenVEX statements. To do this, one adds a reason for why the vulnerability does not apply. These justifications can be found in the OpenVEX spec.
Example
OTP was investigating the CVE FIKA-2026-BROD and found themselves not affected.
We continue from the example in the previous section, that contained zlib with status under_investigation:
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
}
]
}One can update the make/openvex.table with the reason of "code not present", meaning, the component is included
in OTP but the vulnerable code is not present. It is important to note that any statement written in the table
should not be updated, the table is append only.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": {"not_affected": "vulnerable_code_not_present"}
}
]
}To update the OpenVEX statements, run:
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29 | bashIt produces a new entry in the openvex statements for OTP-29 stating that OTP-29 is not vulnerable to the CVE FIKA-2026-BROD.
When OTP is affected by a CVE, one can communicate this using the affected status.
Example
OTP was investigating the CVE FIKA-2026-BROD and found themselves affected.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
}
]
}One can write then in make/openvex.table:
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "affected"
}
]
}where the version affected is written as part of the package url pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc.
Execute the command below to update the OpenVEX statements.
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29 | bashIt produces a new entry in the openvex statements for OTP-29. One can run multiple times the same statement without introducing each time the same statement. (the script makes the operation idempotent).
In some cases, it may be useful to provide additional information to mitigate the vulnerability.
To specify this, write the status value as an object with free text.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": {"affected" : "do not use this component until there is a fix"}
}
]
}and run the otp-compliance script as stated above.
One can specify that the CVE is fixed in a specific version using the fixed keyword in the make/openvex.table statements.
Example
OTP was affected the CVE FIKA-2026-BROD, reported in make/openvex.table.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "affected"
}
]
}OTP creates an emergency patch to fix this vendor dependency, and states that the package url (product and version)
pkg:github/madler/zlib@04f42cecafika2026brod fixes the vulnerability.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "affected"
},
{
"pkg:github/madler/zlib@04f42cecafika2026brod": "FIKA-2026-BROD",
"status": "fix"
},
]
}Execute the command below to update the OpenVEX statements.
.github/scripts/otp-compliance.es vex run --input-file make/openvex.table -b otp-29 | bashAlternatively, one can write the affected and fixed versions in a single object for OTP applications.
"otp-29": [
{
"pkg:otp/erts@10.3.4": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:otp/erts@10.3.4": "FIKA-2026-BROD",
"status": { "affected": "Mitigation message, update to the next release",
"fixed": ["pkg:otp/erts@10.3.20"]}
}
]Some vendor applications may be tied to the runtime system, such as openssl is tied to erts and erl_interface.
When there is a CVE towards a third party tied to an Erlang/OTP package (almost always!),
where Erlang/OTP is not affected (almost all cases of openssl), one can write the following,
where apps is a list of applications not affected, started from their package url version
(14.2.5.10) until implicitly their last version in the tree.
{
"pkg:github/openssl/openssl@0foobar": "CVE-2024-9143",
"status": { "not_affected": "vulnerable_code_not_present",
"apps": ["pkg:otp/erts@14.2.5.10"]}
},In case of wanting to explicitly state that Erlang/OTP is vulnerable or not to a vendor CVE, one can write the following, but the script will not generate range queries due to these been at the sha-1 commit hash level.
{
"otp-29": [
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": "under_investigation"
},
{
"pkg:github/madler/zlib@04f42ceca40f73e2978b50e93806c2a18c1281fc": "FIKA-2026-BROD",
"status": { "affected": "Mitigation message, update to the next release",
"fixed": ["pkg:github/madler/zlib@04f42thiscommitfixesthecve"]}
}
]
}