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

# vulns

> List the vulnerabilities affecting your running images, and where one CVE runs and how exposed it is

## Synopsis

Read-only views over the vulnerabilities found in the images your
workloads run. Findings come from Trivy Operator reports and, when the opt-in
supplychain matcher is enabled, from kguardian's own Grype matcher, which
matches SBOMs. kguardian never blocks or applies anything.

```bash theme={null}
kubectl kguardian vulns list [flags]
kubectl kguardian vulns exposure <id> [flags]
```

For one image's findings, or a CI gate, use
[`images vulns`](/cli/images#images-vulns).

<Warning>
  **Unknown is not safe.** Images no source has scanned are unknown and do not
  appear here, so an empty list is not "no vulnerabilities". An `IN USE` of
  `unknown` means no runtime evidence either way: treat the finding as
  potentially reachable. Tiers rank it as in use.
</Warning>

## In use and tiers

`IN USE` comes from the exec and shared-library capture: which files each
container ran, matched to the packages in the image's SBOM.

| Value                | Meaning                                                                                                                      |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `executed`, `loaded` | A binary the package owns ran, or a library it owns was mapped (including by `dlopen()`).                                    |
| `unknown`            | No evidence either way: no capture for the container, an interpreted-language package (npm, pip, jar), or no SBOM file list. |
| `not-observed`       | Capture covered the container for the whole window and nothing the package owns ran. Not proof it never will.                |

`TIER` ranks findings, most urgent first:

| Tier         | Rule                                                                                                                                           |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `P0`         | In use, in CISA KEV or EPSS at or above 10%, and exposed. A workload with no observed ingress counts as exposed, so a KEV finding there is P0. |
| `P1`         | In use and critical or high, or the P0 factors without exposure.                                                                               |
| `P2`         | In use and medium or low, or high with no fix and not exposed.                                                                                 |
| `Background` | Installed and not observed.                                                                                                                    |

`-` means the tier is not computed yet (the first pass after an upgrade, or a broker without tiers); it never means low risk. The EPSS threshold and exposure
default are Helm values (`broker.supplychain.tiers`); see the
[vulnerability API](/api-reference/endpoints/vulnerabilities#risk-tiers).

## vulns list

Calls `GET /vulnerabilities`: every vulnerability affecting an inventory
image, grouped by id, most severe first. It reads a summary the broker
rebuilds every few minutes; when it was computed is printed on stderr.

| Flag                 | Type   | Description                                                                                       | Default        |
| -------------------- | ------ | ------------------------------------------------------------------------------------------------- | -------------- |
| `-n, --namespace`    | string | Only vulnerabilities affecting this namespace, with counts for it                                 | all namespaces |
| `--severity`         | string | Only these severities, comma-separated                                                            | all            |
| `--fixable`          | bool   | Only vulnerabilities with a fix (`--fixable=false`: only without)                                 | all            |
| `--running`          | bool   | Only vulnerabilities with at least one running workload                                           | off            |
| `--tier`             | string | Only these tiers, comma-separated: `p0,p1,p2,background`                                          | all            |
| `--in-use`           | string | Only these in-use states: `executed,loaded,unknown,installed_not_observed`                        | all            |
| `--kev`              | bool   | Only KEV-listed (`--kev=false`: only those a source says are not; unknown is excluded either way) | all            |
| `--epss-min`         | float  | Only EPSS at or above this probability (0-1)                                                      | off            |
| `--limit`, `--after` |        | Page size (max 500) and cursor                                                                    | `100`          |
| `-o, --output`       | string | `table`, `json` or `yaml`                                                                         | `table`        |

```
TIER  SEVERITY  ID              SCORE  FIXABLE  KEV      IN USE   IMAGES  WORKLOADS  RUNNING  EXPOSED  NAMESPACES  JOIN               PACKAGES
P0    HIGH      CVE-2099-30001  7.5    yes      yes      loaded   1       2          2        1        1           image_id           libfoo1
P1    HIGH      CVE-2099-10003  7.5    no       unknown  unknown  2       3          3        1        2           platform_manifest  libexample
```

A CVE's tier is its most urgent over every affected workload container in
scope, and `IN USE` its strongest state. `EXPOSED` counts workloads with
observed exposure.

Counts are distinct images and workloads, so two sources reporting the same
CVE never count twice. `KEV` `unknown` means no source said either way.
`JOIN` is the weakest match behind the counts: `workload_tag` means some are
by tag only, and the tag may have moved since the scan.

## vulns exposure

Calls `GET /vulnerabilities/{id}/exposure`: the inventory images a
vulnerability affects, the workloads running (or having run) them, and each
workload's observed ingress over the window.

| Flag             | Type   | Description                           | Default |
| ---------------- | ------ | ------------------------------------- | ------- |
| `--window-hours` | int    | How far back traffic counts (max 720) | `168`   |
| `-o, --output`   | string | `table`, `json` or `yaml`             | `table` |

```
CVE-2099-10003  HIGH, no fix available

Images:
  DIGEST               REPOSITORY                  TAGS   PACKAGE     INSTALLED  FIXED  JOIN
  sha256:000000000000  ghcr.io/example/storefront  3.2.0  libexample  1.2.3      -      platform_manifest
  sha256:000000000000  ghcr.io/example/ledger      1.9.4  libexample  1.2.3      -      image_id

Workloads:
  NAMESPACE  WORKLOAD                 CONTAINER  RUNNING  IN USE   EXPOSED  VIA                                     INGRESS FLOWS
  billing    Deployment/catalog-sync  sync       true     unknown  unknown  -                                       0
  billing    Deployment/ledger        api        true     unknown  no       -                                       1
  shop       Deployment/storefront    web        true     unknown  yes      other_namespace,unattributed,public_ip  2

Exposure window: 168h of observed traffic. unknown = no ingress observed (egress alone does not count; inbound UDP is not captured), never "not exposed".
In use: unknown. IN USE is from observed exec and shared-library capture: unknown is potentially reachable, not-observed only means not seen in the window; never treat the package as unreachable.
```

`EXPOSED` is observed traffic, not reachability analysis:

| Value     | Meaning                                                                                                                                                                     |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `yes`     | Ingress seen from another namespace, an unattributed or public IP, or a node IP. `VIA` names which. `node` also covers kubelet probes and NodePort or LoadBalancer traffic. |
| `no`      | Ingress was observed in the window and none of it came from outside. Not proof that none is possible.                                                                       |
| `unknown` | No ingress observed in the window, even if the workload had egress. The controller does not capture inbound UDP, so a UDP-only server looks like this. Never "not exposed". |

`FIXED` lists every fixed version the sources give, in source order. A
vulnerability no inventory image with data lists exits non-zero with a
message saying that is not proof the cluster is unaffected.

`-o json` and `-o yaml` print the broker's response unchanged. Global flags
(`--kubeconfig`, `--context`, `--broker-namespace`, `--broker-service`,
`--broker-token-file`, `--debug`) are listed in the
[CLI overview](/cli/overview). A `401` or `403` prints a hint: these commands
need a token with the `read` scope.

## Examples

```bash theme={null}
# Critical and high, running somewhere in production
kubectl kguardian vulns list -n production --severity critical,high --running

# What to fix first across the cluster
kubectl kguardian vulns list --tier p0

# Where a CVE runs, over the last day of traffic
kubectl kguardian vulns exposure CVE-2024-3094 --window-hours 24

# Every exposed workload, for scripting
kubectl kguardian vulns exposure CVE-2024-3094 -o json | jq '.workloads[] | select(.network.exposed == true)'
```
