skip to content

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