skip to content

Vulnerability DB and Filters

Trivy matches packages against trivy-db, built from distro advisories and GHSA and pulled as an OCI artifact, preferring vendor severity. Interviewers ask about air-gapped mirrors and cutting noise.

on this pageshow

explore

questions

6

In Trivy 0.74, what do --severity and --ignore-unfixed each remove from a vulnerability report, and what do they leave alone?

level: middleimportance: must knowfreq 36%

answer

  1. filters after matching, not before
  2. five levels, all shown by default
  3. status, not severity
  4. shorthand for --ignore-status

basics

~20 s

--severity keeps only findings whose assigned severity is listed, all five levels by default; --ignore-unfixed drops findings whose status is not fixed. Both filter the finished report, so neither changes what was detected or how it was rated.

solid answer

~40 s

Both are report filters applied after matching. `--severity` (`-s`) takes UNKNOWN, LOW, MEDIUM, HIGH and CRITICAL — default all five — and drops any finding whose severity, as Trivy chose it, is not in the list; it filters misconfigurations, secrets and licenses too. `--ignore-unfixed` is shorthand for `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`, so only findings with status `fixed` — a fixed version exists — survive. Neither changes detection or the rating, and both remove findings from JSON and SARIF as well as the table. Unlike an ignore file or VEX, findings dropped this way are not listed by `--show-suppressed`; they simply vanish, so keep an unfiltered report as the record.

code

bash · 2 lines
bash
trivy image --severity HIGH,CRITICAL --ignore-unfixed registry.example.internal/payments/api:1.8.2
trivy image --format json --output full-report.json registry.example.internal/payments/api:1.8.2

go deeper

for a junior

Recall the five severity values, that all are shown by default, and that --ignore-unfixed keeps only findings with a fixed version.

for a middle

Explain the filter order, the status values and which distributions report them, and why --ignore-unfixed equals an --ignore-status list.

for a senior

Show you keep an unfiltered record, know that severity and status filtering leave no suppression trail, and can explain a CVE vanishing because the vendor rated it lower.

for a principal

Argue what a filtered queue means for exposure reporting: hidden affected findings are still risk, so decide who reviews them and when they resurface.

## Where these flags sit Trivy first **detects**: it finds packages in the target and matches each against `trivy-db`, producing findings that already carry a **severity** (chosen from an advisory source) and a **status** (what the distribution says about a fix). Only then does it **filter**. The documented filter order is: by severity, by status, by finding ID (ignore file), by Rego policy, and finally by VEX. `--severity` and `--ignore-unfixed` are the first two steps — prioritisation, not suppression. That ordering explains most surprises: neither flag makes the scan faster, neither changes the database, and neither changes what a finding is rated. ## --severity - Values: `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`; short form `-s`; default is **all five**. - It compares against the severity Trivy **assigned**, which for an OS package is usually the distribution vendor's rating rather than NVD's. A CVE NVD calls HIGH can therefore disappear under `--severity HIGH,CRITICAL` on an image whose vendor rated it Low. - A finding with no severity is treated as `UNKNOWN`, so leaving `UNKNOWN` out also hides findings nobody has rated yet. - It is shared by all scanners: misconfigurations, secrets and licenses are filtered by the same list. ## Vulnerability status values Trivy records a status per finding, and statuses differ by distribution: | Status | Meaning | Reported on | |---|---|---| | `fixed` | a patched version exists | all OSes | | `affected` | affected, no patch released yet | all OSes | | `will_not_fix` | affected, no intention to fix | RHEL | | `fix_deferred` | affected, may be fixed later | Debian, RHEL | | `end_of_life` | component present, no affectedness analysis was performed | Debian, RHEL | | `under_investigation` | defined, never reported as a finding | — | `unknown`, `not_affected` and `under_investigation` exist for completeness; findings with those statuses are not detected at all. ## --ignore-unfixed and --ignore-status `--ignore-unfixed` is documented as a shorthand for `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`: every status except `fixed` is dropped. Two consequences: 1. On distributions that only report `fixed` and `affected`, "unfixed" means `affected`; on RHEL it also removes the vendor's `will_not_fix` decisions. 2. If you pass both flags, Trivy logs a warning that `--ignore-unfixed` is ignored because `--ignore-status` is specified, and uses only your explicit list. `--ignore-status` is the precise tool when you want, say, to hide `will_not_fix` but keep `affected` visible. ## What neither flag does - They do not stop Trivy matching advisories or downloading the database. - They do not change a finding's severity or its source; that is decided at match time. - They do not record what they removed. Findings dropped by an ignore file or by VEX are kept as modified findings and shown by `--show-suppressed`; findings dropped by severity or status are simply gone from table, JSON and SARIF alike. - They are not risk acceptance. An `affected` finding with no patch is still exploitable; hiding it changes the queue, not the exposure. ## Using them without losing evidence A practical pattern is two outputs from one scan configuration: a **triage view** filtered to fixable high and critical findings, which is what a team can act on today, and an **unfiltered JSON report** kept as the record. The gate that fails a build on what remains is part of CI wiring; the filters only decide what "remains" means. Revisit the filtered-out `affected` findings when a fix ships — the next scan after a database update will show them as `fixed` and bring them back automatically. ## Choosing the right control | Goal | Control | Leaves a record? | |---|---|---| | Show only what a team can patch today | `--ignore-unfixed` | no | | Hide one vendor decision, such as `will_not_fix` | `--ignore-status will_not_fix` | no | | Focus on the top of the severity scale | `--severity HIGH,CRITICAL` | no | | Suppress one assessed CVE with a reason | an ignore file entry | yes, via `--show-suppressed` | | Suppress on a supplier's or your own exploitability statement | `--vex` | yes, via `--show-suppressed` | The first three are **views**; the last two are **decisions**. A review that asks "why is this CVE not in the report?" can only be answered from the record for the last two, which is why per-CVE exceptions belong there rather than in a blanket status or severity filter.

  • What happens if you pass both --ignore-unfixed and --ignore-status?
    Trivy logs a warning that `--ignore-unfixed` is ignored because `--ignore-status` is specified, and applies only the statuses you listed. Teams that add `--ignore-status will_not_fix` to an existing `--ignore-unfixed` command therefore silently start seeing `affected` findings again.
  • Why can --ignore-unfixed hide something a team on a Debian base image should act on?
    It drops `end_of_life` and `fix_deferred` findings as well as `affected`. An `end_of_life` status means the component is present but no affectedness analysis was performed — a sign that nobody is assessing that package for you any more, and a reason to move the base image, which the filtered view never shows.

saying these in an interview costs you the question

  • --severity HIGH,CRITICAL makes Trivy skip matching low advisories, so scans run faster
  • --ignore-unfixed hides findings Trivy is unsure about
  • Findings removed by --severity reappear under --show-suppressed
  • --severity always compares against the NVD rating
  • --ignore-unfixed only trims the table; the JSON report still contains everything
open as a page

When a Trivy 0.74 scan logs 'Downloading vulnerability DB', what is it fetching, from where, and when will it fetch again?

level: juniorimportance: should knowfreq 22%

basics

~10 s

It pulls trivy-db, a BoltDB file of compiled advisories shipped as an OCI artifact, from mirror.gcr.io/aquasec/trivy-db:2 and then ghcr.io/aquasecurity/trivy-db:2, caches it, and downloads again once its metadata says a newer build is due.

open as a page

How do you keep Trivy 0.74 vulnerability scans working and current in an air-gapped CI network that cannot reach mirror.gcr.io or ghcr.io?

level: seniorimportance: should knowfreq 17%

basics

~20 s

Mirror trivy-db:2 and trivy-java-db:1 into an internal registry and point --db-repository and --java-db-repository at it, or copy trivy.db and metadata.json into the cache and scan with --skip-db-update. Either way, refreshing the copy is now your job.

open as a page

Trivy 0.74 rates a CVE LOW on a RHEL-based image while NVD rates it HIGH — how did Trivy pick that severity, and how do you prove it?

level: seniorimportance: should knowfreq 26%

basics

~20 s

Trivy takes severity from the advisory source it matched the package against: for an OS package, the distribution vendor, which rates its own build. JSON fields SeveritySource and VendorSeverity show which source won and every source's rating.

open as a page

What does Trivy 0.74's --detection-priority comprehensive change compared with the default precise, and when would you turn it on?

level: middleimportance: nice to knowfreq 9%

basics

~20 s

precise, the default, trusts only distribution advisories for OS-installed files and skips unpinned dependencies; comprehensive adds upstream advisories, scans a range at its minimum and infers Go's stdlib from go.mod, finding more but misfiring more.

open as a page

How do you feed VEX statements to a Trivy 0.74 scan so not_affected findings drop out, and how do you audit what they suppressed?

level: seniorimportance: nice to knowfreq 12%

basics

~20 s

Pass --vex with a local OpenVEX, CSAF or CycloneDX file, or with repo, oci or sbom-ref; a statement whose PURL matches a found package and says not_affected or fixed removes that finding. Adding --show-suppressed lists what VEX removed and why.

open as a page