# Software inventory and SBOM export

Inventory the software in your Linux applications, see what each process loads, match it against OSV advisories, and export CycloneDX, SPDX or OpenVEX.

The collector can list the software inside the applications running on a Linux host, in containers and Kubernetes pods as well as host services, and record which of those components each process actually loads. Tracix matches that inventory against OSV vulnerability advisories. This page shows how to turn both on, read the inventory and its matches, and export it as an SBOM with VEX statements your team writes.

## What the collector reads

The **Software Inventory** integration reads local metadata through each application's own file system and never runs what it inspects. There is no external scanner, and nothing is downloaded or pulled.

| Ecosystem                          | What it reads                                                                                                                |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| OS packages                        | dpkg, APK and RPM package databases, including distroless images, and package notes inside binaries                          |
| Native code                        | ELF executables and libraries, build IDs, and version strings of common statically linked libraries such as OpenSSL and zlib |
| Go and Rust                        | Go build information; Rust crates from `cargo auditable` data, binaries and `Cargo.lock`                                     |
| Node.js                            | `node_modules` trees, pnpm, Yarn Plug'n'Play and `yarn.lock`                                                                 |
| Python                             | Installed distributions, zipapps, PEX and shiv archives, PyInstaller bundles                                                 |
| Java and .NET                      | JAR, WAR and EAR archives with their Maven metadata; `deps.json`, single-file bundles and native AOT images                  |
| Ruby, PHP, Perl, Erlang and Elixir | Gem specifications, Composer packages, CPAN distributions, OTP releases and Hex packages                                     |
| Shipped SBOMs                      | SPDX and CycloneDX documents that ship with the application, matched to the files on disk                                    |

Version strings found in binaries are marked low confidence. Anything the collector can't read or identify is reported as a coverage gap, never as "no components".

## Turn on software inventory

**1. Add the integration**

Add the **Software Inventory** integration to the policy of the collectors on your Linux hosts. Adding integrations needs permission to manage them, which admins have by default; see [Manage collectors with policies](https://tracix.io/docs/collect/collector/policies). Collectors on macOS and Windows in the same policy skip it and run the rest of the policy.

**2. Give the collector the access it needs**

To read every process and its files, the collector needs extra privileges. When the policy includes Software Inventory, the install command the console shows adds them:

* **Linux**: `--enable-software-inventory`, which grants the collector service `CAP_SYS_PTRACE`, `CAP_DAC_READ_SEARCH`, `CAP_BPF`, `CAP_PERFMON` and `CAP_SYS_RESOURCE`. The service keeps running as its own user.
* **Kubernetes**: `softwareInventory.enabled=true`, which runs the collector as root with those capabilities, never as a privileged pod, in the host PID namespace.
* **Docker**: a container in the host's PID namespace with the same capabilities and the host's root mounted read-only.

A collector installed before you added the integration doesn't have this access. Until you reinstall it with these settings, it polls `/proc` and reports what it can't read.

**3. Link processes to services**

The inventory shows up per APM service. A process belongs to a service when it declares `OTEL_SERVICE_NAME` or `service.name` in `OTEL_RESOURCE_ATTRIBUTES`, when its pod's Kubernetes metadata names one, or when you map it in the integration's **Service mappings** field, one mapping per line, such as `k8s_namespace=shop k8s_workload=checkout service_name=checkout`. A process with none of these stays unattributed; Tracix never names a service after an executable.

Two Linux installer flags are separate opt-ins: `--enable-software-docker` lets the collector read Docker's API for container image IDs, which is root-equivalent access, and `--enable-software-probes-sysadmin` adds `CAP_SYS_ADMIN` for execution probes on kernels that refuse them otherwise. Without the extra privileges, the integration falls back to polling `/proc` and reports the applications it can't read as permission denied.

## Turn on vulnerability matching

Matching needs advisories. Connect the [Vulnerability Enrichment](https://tracix.io/integrations/vuln-enrichment) integration under **Collectors › Integrations** (see [Connect an integration](https://tracix.io/docs/collect/integrations#connect-an-integration)). It reads public feeds and needs no credentials.

1. Keep **OSV vulnerability advisories** on.
2. Under **Ecosystems**, keep the ones your applications use: Go, npm, PyPI, Maven, NuGet, crates.io, RubyGems, Packagist, Debian, Ubuntu, Alpine, Red Hat, Rocky Linux, AlmaLinux, SUSE and openSUSE are on by default. Chainguard (about 1 GB) and Wolfi are off unless you run them.
3. Keep **CISA Known Exploited Vulnerabilities** and **FIRST EPSS** on to see exploitation data beside each CVE.

The first load downloads each ecosystem's full set of advisories, which takes minutes for the large ones. After that the integration checks for changes every hour and reloads everything once a week. Tracix matches the inventory against the advisories every 15 minutes for what changed, and every release again once a day.

Each release is looked up the way its source publishes advisories: distribution packages under their distribution release, by source package where the distribution keys advisories that way, and language packages by name. Versions are compared with each ecosystem's own rules. Fedora, Amazon Linux, Oracle Linux, CentOS and Arch have no OSV data, so their packages can't be matched.

## Read the inventory

Open the service under **Applications › APM & Traces** and select its **Components** tab. It has five sections:

* **Inventory**: the components of the current builds of the service, each with its version, ecosystem, how it was identified and its vulnerability matches.
* **Vulnerabilities**: the advisories that match those components.
* **Evidence**: runtime observations of those components in the page's time range.
* **VEX assessments**: the statements your team has written about vulnerabilities in these builds.
* **Capture coverage**: what the collector couldn't see, such as restarts, dropped events or missing permissions.

For containers, the collector marks each component as **application** or **base image**. The application is the packages behind the executables and libraries the container's processes use, what those files contain, and the language packages on the application's own module path. The base image is everything else, which never means unused or safe. The **Inventory** and **Vulnerabilities** sections list the application by default, and their counts follow; select **Show base image** to add the rest. An image the collector hasn't classified yet is listed in full, with a note.

Each component carries evidence labels:

| Label                           | Meaning                                                                                                                 |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **Installed**                   | A package database record installs the component.                                                                       |
| **Present**                     | A file or embedded metadata identifies the component.                                                                   |
| **Declared dependency**         | Metadata names it as a dependency. This alone doesn't mean it is installed or used.                                     |
| **Mapped**                      | A process mapped this native module into memory to run it.                                                              |
| **Loaded**                      | A runtime-specific adapter confirmed that the component loaded.                                                         |
| **Opened**                      | A process opened one of the component's code files. An open alone doesn't prove the code loaded.                        |
| **Executed by probe**           | Execution reached a probe the collector attached to the component.                                                      |
| **Executed in profile**         | The component appeared in a sampled CPU profile. This needs the **Universal Profiling** integration on the same policy. |
| **Not observed in this window** | No execution was seen in the time range. It doesn't mean unused or safe.                                                |

Inventory and runtime evidence are kept for 90 days by default.

## Review vulnerability matches

A match says that an advisory names a component's package and version. In the **Inventory** section, the **Vulnerabilities** column shows each release's highest open severity, its number of open matches, KEV, EPSS and the fixed version, or why it wasn't assessed:

| Value                                 | Meaning                                                                                                                         |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| A severity and a count                | Open matches for this release, led by the highest severity among them.                                                          |
| **No open matches**                   | Every matching advisory is closed by a **Not affected** or **Fixed** assessment of this build.                                  |
| **No matches**                        | Checked, and no advisory affects this version. That isn't a guarantee of safety.                                                |
| **No matches · fixed-only source**    | Red Hat, Rocky Linux, AlmaLinux, SUSE, openSUSE and Alpine publish fixed issues only, so unfixed vulnerabilities aren't listed. |
| **Not assessed yet**                  | Matching hasn't evaluated this release yet.                                                                                     |
| **Not assessed · no package URL**     | There is nothing to look up, such as a native library no package owns.                                                          |
| **Not assessed · no advisory source** | No advisories cover its distribution, release or ecosystem, because OSV has none or you haven't loaded them.                    |
| **Not assessed · version unknown**    | Its version can't be compared, so the advisories that name its package are undetermined, never safe.                            |

The **Vulnerabilities** section lists one row per advisory, with its **Severity**, **Exploitation** (KEV and EPSS), **Affected components**, **Instances**, **Runtime evidence**, **Fixed in** and **VEX** status. Filter it by severity, exploitation, fix, VEX status, runtime evidence, match, advisory source or ecosystem, or search by ID, CVE, component or fix.

* **Severity** comes from the advisory's CVSS score, else the highest CVSS score of its CVEs, else the source's own rating. Without any of them it is **Unknown**, never low.
* **Exploitation** shows whether a CVE is on the CISA Known Exploited Vulnerabilities catalog and its FIRST EPSS score. **No KEV or EPSS record** doesn't mean the CVE isn't exploited.
* An advisory whose version check can't be decided reads **Undetermined**. It is never counted as affected or as safe.

Select an advisory to open its details: the affected releases with their ranges and instances, **Introduced via** (the dependency chains that pulled each release into the build), the runtime evidence and the VEX statements for each build. The runtime evidence follows the page's time range in four steps: **Present**, **Mapped, loaded or opened**, **Executed**, and **Vulnerable function**, which reads **Not checked** because Tracix doesn't check vulnerable functions yet. Evidence can raise a match; nothing observed never lowers one. The matches themselves follow the current inventory, whatever the time range.

### In Security findings

Matches also appear under **Security › Findings**, as one finding per CVE, or per advisory ID when the advisory names no CVE, for each service that runs an affected release. Tracix refreshes them every 15 minutes, applies your VEX assessments when you read the page, and shows the runtime evidence for the selected time range, which defaults to the last 15 minutes. A coverage line says what was and wasn't assessed, so an empty list never hides releases that weren't assessed. As on the **Components** tab, findings only in the base image wait behind **Show base image**.

Reading the matches on the **Components** tab needs the `security.read` permission.

## Export an SBOM

Select **Export** on the **Components** tab and choose what to export:

| Contents           | Formats                                                                                                                                                    |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Inventory JSON** | Tracix inventory JSON v1, with provenance, relationships and completeness                                                                                  |
| **SBOM**           | CycloneDX 1.7 JSON, SPDX 2.3 JSON or SPDX 3.0.1 JSON-LD                                                                                                    |
| **VEX only**       | OpenVEX 0.2.0, CycloneDX 1.7 VEX or the SPDX 3.0.1 security profile                                                                                        |
| **SBOM + VEX**     | CycloneDX 1.7 with embedded VEX, SPDX 2.3 with an OpenVEX 0.2.0 companion file, or SPDX 3.0.1 with native VEX, each listing the build's matched advisories |

Then choose the product builds to include, up to 50, and the scope: the **Full snapshot**, or a **Filtered subset** that matches the inventory's current filters and is labeled partial. Tick **Include evidence bundle (ZIP)** to add the runtime evidence. Every document is validated against the format's pinned schema before it downloads, and several documents download together as a ZIP with a manifest. Exports always cover the whole image, base image included, and each component keeps its layer.

**SBOM + VEX** lists the matched advisories beside the statements your team wrote, without an analysis of their own: a match is not a VEX statement. CycloneDX lists each one with the components it affects, its ratings, and KEV and EPSS as recorded; SPDX 3.0.1 links each component to its vulnerabilities; SPDX 2.3 adds advisory references. The OpenVEX companion carries only your statements. A build with matches but no assessment still exports, and the dialog says its matches are listed without analysis.

A **VEX only** export needs at least one published assessment, and **SBOM + VEX** needs an assessment or a match. Otherwise the dialog says **No VEX assessments available** before anything downloads; Tracix never produces an empty VEX document, because it would read as a clean result.

## Write VEX assessments

A VEX assessment is a statement a person writes about one vulnerability in one exact product build. Runtime evidence can support it; it never decides it.

In the **VEX assessments** section, select **New assessment**, or select **Assess** on an advisory's details. Pick the **Vulnerability ID** from the advisories that match the build, or type any other ID. Choose the **Product build** and optionally the **Assessed component**, then pick a status:

| Status                  | Required with it                                      | Effect on a match           | Exported to CycloneDX and SPDX as       |
| ----------------------- | ----------------------------------------------------- | --------------------------- | --------------------------------------- |
| **Not affected**        | An impact statement; a justification code is optional | Closes it, with your reason | `not_affected` and `VexNotAffected`     |
| **Affected**            | An action statement                                   | Keeps it open               | `exploitable` and `VexAffected`         |
| **Fixed**               | Fix evidence for this exact build                     | Closes it                   | `resolved` and `VexFixed`               |
| **Under investigation** | Optional status notes                                 | Keeps it open               | `in_triage` and `VexUnderInvestigation` |

An assessment speaks about a match when it names the same build and any ID the advisory is known by. An advisory that names several CVEs, such as a Debian security advisory or an Ubuntu security notice, is assessed per CVE: a statement on one CVE covers that CVE only, a statement on the advisory's own ID covers all of them, and the match closes when every CVE is closed. The **VEX** column shows progress, such as **1 of 2 CVEs assessed**. Assessments of the same ID and configuration scope that disagree are flagged as conflicting, and exports refuse them until one is revised or withdrawn.

You can attach supporting facts from the build's inventory and from positive runtime observations; missing samples or probe hits are never offered as evidence. Tracix records the author from your session. To change a published assessment, select **Revise**, which keeps the earlier revision, or **Withdraw**. Assessments never carry over from one build to another. Writing assessments needs the `security.manage` permission, which admins have by default; exporting VEX needs `security.read`.

> **What matching doesn't do**
>
> Tracix matches the inventory the collector reads. It doesn't pull or scan container images or registries, and it doesn't check yet whether a vulnerable function runs. Components without a package URL, and packages from distributions without OSV data, stay unmatched and read **Not assessed**.

## Next steps

- [Detection rules and shadow mode](https://tracix.io/docs/security/detections): Watch the same hosts for threats

- [Install the collector](https://tracix.io/docs/collect/collector/install): Install with the access inventory needs

- [Response actions](https://tracix.io/docs/security/response): Act on what you find
