> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scanoss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Vulnerability Statements (VEX)

> How to state, for each known vulnerability in a project, whether your product is affected: the statuses and justifications, recording and withdrawing statements, the history, and how statements show up in CRA reporting, the CLI and MCP.

A project's **Vulnerabilities** page is where you say, for each known vulnerability in the project's components, whether your product is affected. What you state is what Earnie publishes as VEX (Vulnerability Exploitability eXchange) for the project. The people who receive your SBOM and scan it can then stop flagging what doesn't apply to your product.

To open it, select a project, then **Vulnerabilities** in the sidebar. It sits after **Dependencies**. It appears where your organisation has open-source matching or the enrichment module. Every role that can read the project can open it.

## What a Row Is

A row is one CVE in one exact component version of the project's current inventory. That inventory is the latest completed scan of the default branch, its declared dependencies, an imported SBOM, and the resolved dependency graph. Earnie reads the rows fresh each time and doesn't store them.

Each row shows:

* the CVE, with **KEV** when it's on the CISA Known Exploited Vulnerabilities list
* the component and version
* the severity and the EPSS score
* the version that fixes it
* its status, its justification, and who last updated it

A statement is stored apart from scans, so a new scan never changes it. A statement is also about one version: a statement about version 2.14.1 says nothing about 2.15.0, and a new version starts with nothing stated.

## Statuses

| Status | What it means |
| - | - |
| **Not decided** | No one has stated anything. The page opens on these rows, because they're the work left. Earnie never publishes them: staying silent isn't the same as saying "under investigation". |
| **Under investigation** | You're still assessing whether the product is affected. |
| **Affected** | The product can be exploited through this vulnerability. An **Action statement** says what its users should do, and it's required. |
| **Not affected** | The product can't be exploited through it. A justification is required. An impact statement in your own words is optional. |
| **Fixed** | This version contains the fix. |

### Justifications for Not Affected

| Justification | What it means |
| - | - |
| **Component not present** | The component isn't part of the product. |
| **Vulnerable code not present** | The component is there, but the vulnerable code isn't. |
| **Not in the execute path** | The vulnerable code is there but is never run. |
| **Cannot be controlled by an attacker** | An attacker can't reach or influence the vulnerable code. |
| **Mitigations already exist** | The product already guards against it. |

## Finding the Rows You Need

* **Switch status.** The segments at the top show how many rows each status holds, for the other filters you've set.
* **Filter.** **Severity** keeps the severities you choose, **Known exploited** keeps the KEV rows, and **Search vulnerabilities** matches part of a CVE ID, an alias, or a component.
* **Share a view.** The address holds your filters, so you can paste a link to a view.
* **Load more.** A long list loads fifty rows at a time. Choose **Show more** for the next page.

## Why It's Here

A row's panel starts with **Why it's here**, so you can decide with the context in front of you. It says which inventory brought the component into the project:

* **Matched in your code**
* **Declared dependency**
* **From an imported SBOM**
* **Resolved dependency**
* **Component used by crypto or AI code**

A component can have several. When the project's dependency graph knows the package, the panel says **Direct dependency**, or lists the chains that pull it in, from a direct dependency down to the package, with the manifest that declares it. It shows the shortest few chains and says when there are more.

The panel also links onward:

* **Open in Dependencies** opens the package in the graph.
* **Open in Review** opens a component your code matched in the Review Workspace.
* **Advisory** opens the public advisory in a new tab, with the other IDs the vulnerability is known by.

## Recording and Withdrawing Statements

Admins and Operators can record and withdraw statements. A Viewer can read the list and every history, and the page says who can record.

* **Record one statement.** Select a row to open its panel. Choose a status, fill in what it asks for, and choose **Record statement**. The panel closes and the row moves to its new status.
* **Record many at once.** Tick several rows and choose **Record statement** in the bar above the table. One statement goes onto every selected row, all together or none. Changing a filter clears the selection.
* **Withdraw a statement.** In a row's panel, choose **Withdraw statement**. Or tick rows that all have one and choose **Withdraw**. Earnie asks first. The row goes back to **Not decided** and stops being published.

Withdrawing erases nothing. The panel's **History** keeps every revision, newest first, with who made it, whether a person or an agent did, and when.

> [!NOTE]
>
> **A statement is a fact about the product, not a waiver.** It never approves a policy violation. Policy Approvals stay the place for that. See [When the gate blocks a merge](https://docs.scanoss.com/en/latest/earnie/using-earnie/merge-gate.md). A policy only treats a CVE differently when its rule reads the VEX status, as the two built-in vulnerability policies below do.

## Statements in Policies

A policy can read a statement through the **VEX status** field of a vulnerability (`vulnerability.vex_status`). Its values are `not_affected`, `affected`, `fixed`, `under_investigation` and `undecided`. A CVE with no statement, or a withdrawn one, is always `undecided`, so a rule never has to check that the field is there. Recording or withdrawing a statement re-evaluates the project's policies.

The built-in policies **Block known exploited vulnerabilities** and **Block high-severity vulnerabilities** skip a CVE whose statement is in their **Ignored VEX statuses** parameter, which is **Not affected** and **Fixed** by default. If a fixed CVE should keep blocking until the component is upgraded, remove **Fixed** from that parameter. A policy you write sees every CVE until you add a clause such as `!(v.vex_status in ["not_affected", "fixed"])`.

## Statements in Counts

A project's CVE counts (the project summary, the **High CVEs** column of the projects list, and what a coding agent reads) leave out a CVE the project has stated **Not affected** or **Fixed** on every version of the component that carries it. A CVE still open on any version counts. The dashboard's CVE cards are recorded at each scan, so they show a new statement from the project's next scan. The **Vulnerabilities** page always lists every CVE, stated or not.

## Statements in Exports

A CycloneDX export carries each CVE's statement as of the moment the export was made, in the vulnerability's `analysis`: **Not affected**, **Affected** (exploitable), **Fixed** (resolved) or **Under investigation** (in triage), with the justification and your statement text. A CVE with no statement carries none. SPDX exports do not carry statements.

To give a scanner your statements, export **VEX (CycloneDX)** with the SBOM. The VEX file lists only the CVEs you have a statement for, and points at the components of the SBOM exported with it, so a scanner such as Trivy can read both (`trivy sbom sbom.cdx.json --vex vex.cdx.json`) and stop reporting what you stated not affected or fixed. The CRA compliance package includes the VEX file too.

If your scanner reads OpenVEX instead, export **VEX (OpenVEX)**: the same statements, with each product named by its package URL, so it needs no SBOM beside it.

## Statements in CRA Reporting

Where CRA reporting is switched on for your deployment, the statement for a component and CVE appears next to the decision you make about an exposure. It is context only: Earnie never confirms, dismisses, or closes anything because of a statement.

**Deciding about an exposure.** The **To decide** view of **CRA reporting** lists every known exploited vulnerability that nobody has decided about yet. Each row shows the CVE, the component and version, the project, when CISA listed it (**KEV**), whether it's known in ransomware, and the project's vulnerability statement in words, such as **Not affected, not in the execute path**, or **No statement**.

Members who can decide on CRA cases (the Admin role) see two buttons on each row:

| Button | What it does |
| - | - |
| **Confirm** | Opens **Confirm exposure**. Write the initial assessment (required): why you consider the exposure to affect your product. Confirming records that you're aware the vulnerability may be reportable, and starts the reporting deadlines. |
| **Dismiss** | Opens **Dismiss exposure**. Choose a **Reason** (**Not in the shipped product**, **Not reachable**, **Not exploited in the product**, **Already mitigated**, or **Other**) and write a **Note** (required). No deadline starts. |

Anyone else sees one line that says who decides, and no button.

**The suggested dismissal.** When the project's statement for that component and CVE is **Not affected**, the dismiss form opens with the matching reason and the statement's impact statement as the note, under the line **Prefilled from the vulnerability statement**. It's a suggestion. Change either field, and choose **Dismiss exposure** yourself. Earnie never dismisses on a statement alone. Choosing the button twice, or retrying after a failure, records the decision once. If someone decided about the exposure in the meantime, the form says so and records nothing.

**On a case.** A case page shows the component's **Vulnerability statement** for that project, with a link to open it on the **Vulnerabilities** page, or *No statement recorded*. Members who can decide on CRA cases can **Close case** or **Reopen case** at the top of the page. **Close case** asks for a reason, **No longer reportable** or **Withdrawn**, and takes an optional note. **Reopen case** asks for a note (required) and opens the case again on its original deadlines.

## From a Coding Agent or the Command Line

Coding agents usually record statements from where the code is. They use [MCP](https://docs.scanoss.com/en/latest/earnie/mcp/tools.md) or the [`earnie vulnerabilities`](https://docs.scanoss.com/en/latest/earnie/using-earnie/earnie-cli#vulnerability-statements) command, with an API key that holds the `vulnerabilities:decide` permission. The page then shows those statements as made by an agent.

## Who Can Do What

| Capability | Admin | Operator | Viewer |
| - | - | - | - |
| Read the list and every history | ✓ | ✓ | ✓ |
| Record or withdraw a statement | ✓ | ✓ | — |
| Confirm or dismiss a CRA exposure, close or reopen a CRA case | ✓ | — | — |

An API key can hold `vulnerabilities:decide`, and reading vulnerabilities needs `findings:read`. See [API keys](https://docs.scanoss.com/en/latest/earnie/administration/api-keys.md#scope-reference).

## What's Next

[Triage the findings](https://docs.scanoss.com/en/latest/earnie/using-earnie/triaging-findings.md) a scan raised, or see [how each package reached your project](https://docs.scanoss.com/en/latest/earnie/using-earnie/dependencies.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.