# CVE Scanning

CVE scanning lets <!-- -->nRF Cloud<!-- --> continuously check the software components in your firmware against known security vulnerabilities. You attach a Software Bill of Materials (SBOM) to a software version, and <!-- -->nRF Cloud<!-- --> matches its components against public vulnerability data, flags affected CVEs, and gives you a place to triage each CVE and record why it does or does not apply to your product. This supports vulnerability-handling obligations such as those in the EU Cyber Resilience Act (CRA).

note

CVE scanning is available on request. [Contact us](https://mflt.io/contact-support) to enable it for your organization if you don't see a **Security Services** section.

## How it works[​](#how-it-works "Direct link to How it works")

CVE scanning builds directly on the [SBOM](/docs/platform/sbom.md) feature:

1. You attach an SBOM to a software version (see [Getting started](#getting-started)).

2. nRF Cloud
   <!-- -->
   parses the SBOM's SPDX data and extracts its components, normalizing each component's vendor, product, and version so they can be matched.

3. Each component is matched against known vulnerable version ranges sourced from:

   <!-- -->

   * the [**National Vulnerability Database (NVD)**](https://nvd.nist.gov/),
   * [**GitHub Security Advisories (GHSA)**](https://github.com/advisories) for the upstream projects behind Nordic nRF Connect SDK modules, and
   * the [**CISA Known Exploited Vulnerabilities (KEV)**](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) catalog, which flags CVEs that are being actively exploited in the wild.

4. Matches become **CVEs** you can review and triage.

Scans run automatically when you upload an SBOM, and again whenever the underlying vulnerability data changes. A version that is clean today can surface a new CVE later, with no action on your part. You can also trigger a re-scan manually from the SBOM's page.

## Getting started[​](#getting-started "Direct link to Getting started")

### 1. Upload an SBOM[​](#upload-an-sbom "Direct link to 1. Upload an SBOM")

CVE scanning requires an SBOM for each software version you want to scan. You can attach one from the **Security Services** section or upload it as part of your build. See [SBOM](/docs/platform/sbom.md) for the full upload instructions, including uploading from CI/CD and generating SBOMs for common platforms.

note

CVE scanning parses **SPDX** SBOMs (SPDX JSON and SPDX tag-value). Other formats can be stored against a software version but are not scanned for vulnerabilities.

### 2. Review CVEs[​](#review-cves "Direct link to 2. Review CVEs")

Open the **Security Services** section to see one row per active software version, with its SBOM status and a summary of CVEs by severity. Select a version to open its CVEs.

Each CVE shows its ID, severity, vulnerable library, when it was first detected, and its CVE Triage Status (**"—"** until you triage it). CVEs are sorted with actively-exploited (KEV) CVEs first, then by severity, and you can filter them with the tabs above the table: **All**, **Exploitable**, **Critical**, **High**, and **Untriaged**.

### 3. Triage each CVE[​](#triage-each-cve "Direct link to 3. Triage each CVE")

For each CVE, record whether it actually affects your product. Triage decisions follow the Vulnerability Exploitability eXchange (VEX) model and are kept as an append-only history, so you retain an audit trail of who decided what and when. See [Triaging CVEs](#triaging-cves) for the available states and justifications.

### 4. Remediate[​](#remediate "Direct link to 4. Remediate")

When a CVE is exploitable, ship a new software version with the affected component updated and attach its SBOM. The new version's scan reflects the fix, and you can deploy it with [OTA](/docs/platform/ota.md).

## Triaging CVEs[​](#triaging-cves "Direct link to Triaging CVEs")

Each CVE is **untriaged** until you assess it. Until then its CVE Triage Status shows "—" and it appears under the **Untriaged** filter. To triage, open a CVE and choose **Triage CVE → Add triage review**, then set a **State** (one disposition applies to every affected component on that software version):

| State            | Meaning                                                             |
| ---------------- | ------------------------------------------------------------------- |
| in triage        | The vulnerability is actively being reviewed.                       |
| affected         | The vulnerability applies to your product and needs remediation.    |
| not affected     | The vulnerability does not apply. Requires a justification (below). |
| false positive   | The component was matched incorrectly.                              |
| resolved (fixed) | The CVE has been addressed.                                         |

When you mark a CVE **not affected**, choose a justification:

| Justification                   | Use when                                                                   |
| ------------------------------- | -------------------------------------------------------------------------- |
| Code not present                | The vulnerable component is not actually in this build.                    |
| Code not reachable              | The vulnerable code is present but never executed.                         |
| Requires configuration          | The vulnerability is only exploitable under a configuration you don't use. |
| Requires dependency             | Exploitation depends on a dependency you don't ship.                       |
| Requires environment            | Exploitation depends on an environment that doesn't apply.                 |
| Protected by compiler           | Compiler protections neutralize the vulnerability.                         |
| Protected at runtime            | Runtime protections neutralize the vulnerability.                          |
| Protected at perimeter          | Perimeter controls prevent the attack from reaching the device.            |
| Protected by mitigating control | Another control mitigates the vulnerability.                               |

You can also record a planned **response** for a CVE: Update, Rollback, Workaround available, Will not fix, or Can not fix.

Every disposition change is recorded in the CVE's **Triage Log** as an append-only history of who changed what and when.

## Severities[​](#severities "Direct link to Severities")

CVEs are labelled **Critical**, **High**, **Medium**, or **Low**. The severity, CVSS score, and CVSS version shown come from the vulnerability's source (NVD or GHSA); <!-- -->nRF Cloud<!-- --> does not compute its own scores.

## Limitations[​](#limitations "Direct link to Limitations")

* **SPDX only.** SBOMs must be SPDX (JSON or tag-value) to be scanned. Other formats can be stored but are not scanned.

* **Components need a CPE 2.3 identifier.** A component is only scanned if a vendor and product can be resolved from a [Common Platform Enumeration (CPE)](https://nvd.nist.gov/products/cpe). The CPE must use the CPE 2.3 formatted string binding and appear as a `cpe23Type` external reference in the SPDX package. Requirements:

  * It must start with `cpe:2.3:`. The older CPE 2.2 URI binding (`cpe:/...`) will not be accepted.
  * It must have at least six colon-separated fields: `cpe:2.3:<part>:<vendor>:<product>:<version>:...`.
  * The **product** field must be a real value, not empty and not a wildcard (`*` or `-`). A component whose product resolves to a wildcard cannot be matched.

  Components without a resolvable CPE are stored but not matched, so coverage depends on the quality of your SBOM. For example:

  | Component                             | Version | CPE                                             |
  | ------------------------------------- | ------- | ----------------------------------------------- |
  | OpenSSL                               | 3.1.4   | `cpe:2.3:a:openssl:openssl:3.1.4:*:*:*:*:*:*:*` |
  | curl                                  | 8.6.0   | `cpe:2.3:a:haxx:curl:8.6.0:*:*:*:*:*:*:*`       |
  | (a component with no CPE in the SBOM) | —       | not matched                                     |

* **Disclosure lag.** A CVE only appears once it is published by an upstream source, so newly-disclosed vulnerabilities can take time to surface.

## Component scan status[​](#component-scan-status "Direct link to Component scan status")

The scan status indicates the result of <!-- -->nRF Cloud<!-- --> parsing the SBOM and attempting to find reported CVEs.

| Status                                               | Description                                                                                                                                                                                                                                                  |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Successful                                           | The SBOM was parsed and scanned without error.                                                                                                                                                                                                               |
| Scanning                                             | The component is currently being scanned for CVEs.                                                                                                                                                                                                           |
| Failed, scan couldn't complete                       | An error occurred while scanning this component. Try re-scanning the SBOM. If the problem persists, [contact us](https://mflt.io/contact-support).                                                                                                           |
| Skipped, no identifier to match against CVE database | A version or CPE couldn't be extracted from the SBOM. Check the component's version and CPE against the requirements in [Limitations](#limitations), then upload the corrected SBOM. If the problem persists, [contact us](https://mflt.io/contact-support). |
| Skipped, CPE doesn't specify a product               | The component's CPE names a vendor but its product field is empty or a wildcard, and no other identifier in the SBOM supplied a product. Update the CPE in the SBOM to include the product.                                                                  |
| Skipped, CPE couldn't be parsed                      | The component's CPE is malformed, or both its vendor and product are wildcards, and no other identifier in the SBOM supplied a product. Correct the CPE in the SBOM.                                                                                         |
| Skipped, no known advisory source                    | The component does not currently have a parsable source for vulnerability reports. See [known components](#known-components) for details about specific components.                                                                                          |

### Known components[​](#known-components "Direct link to Known components")

* `nrfconnect/sdk-nrf` (nRF Connect SDK): Nordic publishes [security advisories](https://docs.nordicsemi.com/r/bundle/struct_sa/page/struct/sa.html). Review that page for the latest reported advisories.
* `memfault/memfault-firmware-sdk`: [Contact us](https://mflt.io/contact-support) if your team has concerns.
