skip to content

Trivy

Trivy is one binary that scans images, filesystems, repositories and IaC for CVEs, misconfigurations, secrets and licenses. Interviewers use it to test running a scanner without drowning in noise.

on this pageshow

explore

questions

28

Does a Trivy 0.74 scan fail a CI job by default when it finds a CRITICAL vulnerability, and what makes it fail?

level: juniorimportance: must knowfreq 42%

answer

  1. the default exit status
  2. a flag that names the code
  3. filters run before the decision
  4. secrets count too, not just CVEs

basics

~10 s

No. Trivy 0.74 exits 0 whatever it finds; setting --exit-code to a non-zero value makes it exit with that code when any finding survives filtering, and --severity HIGH,CRITICAL decides which findings survive.

solid answer

~40 s

By default `--exit-code` is `0`, so a scan that reports a hundred CRITICALs still exits 0 and the job goes green. Set `--exit-code 1` (or any non-zero code) and Trivy exits with it when anything is left after filtering: a vulnerability, a FAIL misconfiguration, a secret or a license finding. `--severity HIGH,CRITICAL` narrows what is left, and it filters the report too, so the MEDIUMs vanish from the output as well as from the gate. Ignore files, `--ignore-unfixed`, an `--ignore-policy` and VEX all run before the decision. `--exit-on-eol` is a separate gate for an end-of-life base OS and is checked first. Because Trivy also exits 1 on a fatal error such as a failed database download, a distinct code like `--exit-code 2` lets the pipeline tell findings from a broken scan.

code

bash · 9 lines
bash
status=0
trivy image --severity HIGH,CRITICAL --exit-code 2 --exit-on-eol 3 \
  registry.example.internal/shop/api:1.4.2 || status=$?
case "$status" in
  0) echo "gate passed" ;;
  2) echo "HIGH or CRITICAL findings remain"; exit 1 ;;
  3) echo "base OS is end-of-life"; exit 1 ;;
  *) echo "trivy itself failed (exit $status)"; exit 1 ;;
esac

go deeper

for a junior

Remember that Trivy exits 0 by default and only fails a job when --exit-code is non-zero, and that --severity HIGH,CRITICAL limits what can fail it.

for a middle

Explain the filter order behind the decision (severity, status, ignore file, Rego, VEX) and that secrets, FAIL misconfigurations and licenses count alongside vulnerabilities.

for a senior

Show you keep the gate trusted: a distinct exit code so a failed database download is not mistaken for findings, --exit-on-eol as its own signal, and a separate full report because --severity trims the output.

for a principal

Frame the gate as something teams must keep switched on: which finding classes fail it, how waivers are scoped, and how one checked-in trivy.yaml keeps local and CI runs identical across repositories.

## The default: Trivy reports, it does not judge A **Trivy** scan has two outputs: the report (table, JSON, SARIF and so on) and the process **exit status**. A CI system only looks at the exit status. In Trivy 0.74 the `--exit-code` flag defaults to `0`, so the scan exits 0 whether it found nothing or a hundred CRITICAL vulnerabilities; a job that runs `trivy image` with no gate flags always goes green, and the findings are information for whoever reads the log. Failing the job is an explicit opt-in, and how narrowly you opt in decides whether teams keep the gate: a gate that fires on every LOW in a base image is the one that gets commented out. ## What `--exit-code` counts Setting `--exit-code` to a non-zero value means "if any finding remains after filtering, exit with this code". Trivy evaluates the final, already-filtered result set, and the check is broader than vulnerabilities: | Finding class | Counts toward `--exit-code` when | |---|---| | Vulnerability | any remains after filtering | | Misconfiguration | its status is FAIL; passed checks never count | | Secret | any remains after filtering | | License | any remains, which needs the license scanner enabled | The default `--scanners` value is `vuln,secret`, so a plain `trivy image --exit-code 1` fails on a hard-coded access key as readily as on a CVE. That surprises teams who think of Trivy as only a CVE scanner. ## What runs before the decision The exit decision happens after the filters, which Trivy applies in this order: 1. **Severity**: `--severity` (default: all five of `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL`) keeps only the listed levels. Which severity a finding carries, and which source it came from, is the vulnerability-database topic; here it is simply the value Trivy assigned. 2. **Status**: for example `--ignore-unfixed`, which drops vulnerabilities that have no fixed version yet. 3. **Ignore file**: IDs listed in `.trivyignore`, or in a YAML ignore file named with `--ignorefile`. 4. **Rego**: an `--ignore-policy` file. 5. **VEX**: statements supplied with `--vex`. Two consequences matter in CI: - `--severity` filters the **report** as well as the gate. A run with `--severity HIGH,CRITICAL` writes a report with no MEDIUM or LOW rows at all, so a team that also wants the full picture runs a second, non-gating scan or keeps a full JSON report. - A filtered or waived finding cannot fail the build. That is the point of the filters, and it is why the waivers themselves deserve review. ## `--exit-on-eol`: a separate gate `--exit-on-eol` takes its own code and fires when Trivy detects that the scanned operating system has reached end of service or life. It is checked **before** `--exit-code`, so an end-of-life base image returns the EOL code even when vulnerabilities also remain. Giving each gate its own number lets the pipeline report which rule tripped. ## Telling findings from a broken scan When Trivy itself fails (a rate-limited database download, an image it cannot pull, a config file it cannot parse) it logs a fatal error and exits **1**. If the gate also uses `--exit-code 1`, a red job could mean "HIGH findings" or "the scanner never ran", and people learn to press re-run until it goes green. A distinct code such as `2` keeps the two apart; both still fail the job, which is the safe direction. Keeping Trivy's database in a CI cache, which the official GitHub Action does by default, cuts down those download failures; mirrors and offline database handling are a separate topic. ## Keeping the gate in one place Trivy reads `trivy.yaml` from the current directory by default, or another file named with `--config`. The gate settings are top-level keys there (`exit-code`, `exit-on-eol`, `severity`), so a developer's local run and the CI run behave the same. Precedence runs CLI flag, then `TRIVY_*` environment variable, then the config file, then the built-in default. ## Mistakes that get a gate switched off - Gating on every severity of a fresh base image, so the first run fails on dozens of LOW findings nobody can fix this sprint. - Reusing exit code 1, so a rate-limited database download looks like a vulnerability and gets re-run until green. - Forgetting that secrets are scanned by default, then discovering the gate on a test fixture that holds a fake key. - Setting the gate in a wrapper's environment and in `trivy.yaml` with different values, so local runs and CI disagree. A minimal gate on one line: ```bash trivy image --severity HIGH,CRITICAL --exit-code 2 registry.example.internal/shop/api:1.4.2 ```

  • Why might a team run Trivy twice in the same CI job?
    Because `--severity` filters the report as well as the gate. A run with `--severity HIGH,CRITICAL --exit-code 1` writes a report with the MEDIUM and LOW findings missing. Teams that want a complete record run once with `--exit-code 0` and every severity to produce a JSON or SARIF report, then once more with the gate flags; the second run reuses the cached database.
  • Where should the gate's flags live so a developer's local Trivy run matches CI?
    In a checked-in `trivy.yaml`, which Trivy reads from the current directory by default; `exit-code`, `exit-on-eol` and `severity` are top-level keys. A CLI flag or a `TRIVY_*` environment variable still overrides the file, so a CI wrapper that sets either one silently changes the gate. An explicit `--config` path that does not exist stops Trivy with an error.
  • Does `--exit-code 1` fail a `trivy image` run that found only a hard-coded secret?
    Yes. The default `--scanners` value in Trivy 0.74 is `vuln,secret`, and any secret finding that survives filtering counts toward the exit code exactly like a vulnerability. Teams that only want CVEs to gate either pass `--scanners vuln` or waive the specific secret rule, but a real leaked key is usually the finding most worth failing on.

saying these in an interview costs you the question

  • Trivy fails the build by default whenever it finds a CRITICAL vulnerability.
  • --severity only changes the exit decision; the report still lists every severity.
  • --exit-code only reacts to vulnerabilities, never to secrets or failed misconfiguration checks.
  • Exit code 1 from Trivy always means vulnerabilities were found.
  • A passed misconfiguration check counts toward the exit code.
open as a page

With Trivy 0.74, how do you scan a folder of Terraform, Kubernetes and Dockerfiles for misconfigurations, and how do you read one finding?

level: juniorimportance: must knowfreq 32%

basics

~20 s

Run trivy config on the folder; it detects each file's type and applies the built-in trivy-checks bundle. Each failure gives severity, check ID, title, an AVD link and file lines. fs, image and repo skip this unless --scanners misconfig is set.

open as a page

With Trivy, how do you generate an SBOM for a container image and later re-check it against new advisories without pulling the image?

level: juniorimportance: must knowfreq 34%

basics

~20 s

Run trivy image with --format cyclonedx, spdx or spdx-json and --output to save the package inventory with the release. Later, trivy sbom on that file matches the recorded packages against Trivy's current vulnerability database, with no image pull.

open as a page

Why does Trivy 0.74 report different vulnerabilities for one service when you run `trivy fs`, `trivy repo`, `trivy image` and `trivy rootfs` against it?

level: middleimportance: must knowfreq 34%

basics

~20 s

Each Trivy subcommand enables a different set of analyzers: fs and repo read pre-build lockfiles, while image, rootfs and vm read post-build evidence such as OS package databases, installed package metadata, Go binaries and JARs, and skip most lockfiles.

open as a page

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%

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.

open as a page

In Trivy 0.74, which checks does `trivy image` or `trivy fs` run by default, and how does `--scanners` change them?

level: juniorimportance: should knowfreq 24%

basics

~20 s

Trivy 0.74's image, fs, repo, rootfs and vm subcommands default to vulnerability and secret scanning. Misconfiguration and license checks stay off until listed in --scanners, and that flag replaces the default list rather than adding to it.

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

In Trivy 0.74, how do .trivyignore and .trivyignore.yaml differ when you must waive one CVE for one package until a date?

level: middleimportance: should knowfreq 28%

basics

~20 s

A .trivyignore line waives an ID for every package, file and scanner, optionally until an exp: date. The experimental .trivyignore.yaml, loaded only through --ignorefile, scopes the waiver by purls or paths and adds expired_at and a statement.

open as a page

A Trivy 0.74 pipeline must feed a JUnit test report, a code-scanning dashboard and a dependency graph — which --format does each need?

level: middleimportance: should knowfreq 21%

basics

~20 s

JUnit needs --format template with --template @contrib/junit.tpl, the dashboard needs --format sarif, and the dependency graph needs --format github, a dependency snapshot rather than a findings list. Keep a --format json report as the complete record.

open as a page

How do you add an internal-token rule to Trivy 0.74's trivy-secret.yaml, and how do allow-rules cut noise without hiding real keys?

level: middleimportance: should knowfreq 20%

basics

~20 s

Add a rules entry with id, category, title, severity and a Go regex, plus keywords for speed. Allow-rules drop a hit by matched text or file path, globally or per rule. Keep them narrow: built-in ones already skip test and example paths.

open as a page

A Trivy 0.74 config scan reports nothing on a Terraform security group whose CIDR comes from prod.tfvars — why, and what does --tf-vars change?

level: middleimportance: should knowfreq 15%

basics

~20 s

Trivy evaluates HCL without running Terraform and reads root variable values only from defaults, TF_VAR_ variables and files passed with --tf-vars. Unset variables become unknown, so a check cannot see 0.0.0.0/0. Passing --tf-vars prod.tfvars supplies the real value.

open as a page

A Trivy 0.74 CI step runs `trivy image --format cyclonedx --output sbom.cdx.json --exit-code 1 --severity CRITICAL app:1.4` and never fails — why?

level: middleimportance: should knowfreq 22%

basics

~20 s

An SBOM output format (cyclonedx, spdx or spdx-json) empties Trivy's scanner list unless --scanners was set explicitly, so the run only inventories packages. With no findings, --exit-code has nothing to trigger on; add --scanners vuln.

open as a page

In Trivy 0.74, how does `--scanners license` decide whether a detected license is CRITICAL, HIGH or UNKNOWN, and how do you change that?

level: middleimportance: should knowfreq 18%

basics

~20 s

Trivy sorts each license into Google's license categories and maps them to severity: forbidden CRITICAL, restricted HIGH, reciprocal MEDIUM, notice, permissive and unencumbered LOW, unrecognised UNKNOWN. The lists live under license in trivy.yaml; --ignored-licenses drops named licenses.

open as a page

Why can Trivy 0.74's `trivy image` scan a different copy of the same tag on a laptop than in CI, and which flags pin that choice?

level: middleimportance: should knowfreq 15%

basics

~20 s

trivy image scans the first copy it finds, trying Docker Engine, containerd, Podman and then the registry, so a stale local pull or another architecture can be scanned. --image-src fixes the source order and --platform chooses the architecture.

open as a page

A Trivy 0.74 image scan reports a private key in a file your Dockerfile deletes in a later step — is that a false positive?

level: seniorimportance: should knowfreq 14%

basics

~20 s

No. Trivy scans each image layer separately and keeps secrets from every layer, even when a later layer deletes the file, because that layer still ships in the image. The finding names the instruction that added it; rotate the key.

open as a page

Trivy 0.74's `trivy sbom` reports no OS-package vulnerabilities for a stored CycloneDX SBOM of a Debian-based image — what in the file do you check?

level: seniorimportance: should knowfreq 12%

basics

~20 s

Check for an operating-system component naming the distribution and its version, and for a purl on every package component. Without the first, Trivy has no distribution advisories to match; components lacking a usable purl are skipped. Neither stops the scan.

open as a page

In Trivy 0.74 client/server mode, what does `trivy server` do, what still runs on the client, and where does each side keep its cache?

level: seniorimportance: should knowfreq 12%

basics

~20 s

The Trivy server holds and refreshes the vulnerability database and matches packages; the client still pulls the artefact, extracts packages and runs secret and misconfiguration checks. Both use --cache-dir, and several servers must share a Redis scan cache.

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

A team runs `trivy convert --format cyclonedx` over last year's Trivy JSON reports to re-check old releases — why does that not answer the question?

level: middleimportance: nice to knowfreq 8%

basics

~20 s

trivy convert re-renders an existing Trivy JSON report into another format without consulting the vulnerability database, so it repeats last year's findings. Re-checking needs trivy sbom on a stored SBOM, which matches the packages against today's advisories.

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

A trivy-action step sets severity HIGH,CRITICAL, exit-code 1 and format sarif, yet fails the build on MEDIUM findings — why, and how do you fix it?

level: seniorimportance: nice to knowfreq 9%

basics

~20 s

trivy-action unsets the severity input for SARIF output unless limit-severities-for-sarif is true, so without a config-file severity Trivy reports and gates on every level. Set that input to true, or split reporting and gating into two steps.

open as a page

After the March 2026 trivy-action tag compromise, what should a team that ran Trivy in CI check, rotate and change?

level: seniorimportance: nice to knowfreq 6%

basics

~20 s

Check whether any job ran a trivy-action tag below 0.35.0, an unpinned setup-trivy or a malicious Trivy 0.69.4, 0.69.5 or 0.69.6 in March 2026; if so, rotate every secret it could reach, then pin all three immutably.

open as a page

A Trivy 0.74 CI job logs 'Falling back to embedded checks' yet still passes — which misconfiguration checks did it actually run?

level: seniorimportance: nice to knowfreq 6%

basics

~20 s

It ran the checks embedded in the Trivy binary when that release was built, because pulling the trivy-checks bundle failed. The scan completes normally, so newer checks are silently missing until the bundle is reachable or mirrored.

open as a page

Your platform team is replacing tfsec with Trivy 0.74 for Terraform checks — what carries over unchanged, and what must you rework?

level: seniorimportance: nice to knowfreq 9%

basics

~20 s

Trivy carries tfsec's Terraform engine and still parses tfsec:ignore comments with their :exp: expiries. Rework the command, the exit code, ignore IDs that no longer match, repo-wide exclusions, and custom checks, which Trivy loads as Rego.

open as a page

With `trivy image --sbom-sources oci`, Trivy 0.74 reports an image's vulnerabilities in seconds without analysing its layers — what did it scan, and when is that a problem?

level: seniorimportance: nice to knowfreq 5%

basics

~20 s

Trivy found an SBOM attached to the image's digest through the registry's referrers API and scanned that document instead of the layers. The result is only as complete and trustworthy as that SBOM, and Trivy does not check who signed it.

open as a page

What does a `trivy k8s` run in Trivy 0.74 read and create in a cluster, and how do you keep its report usable?

level: seniorimportance: nice to knowfreq 9%

basics

~20 s

trivy k8s lists cluster resources through a kubeconfig context, scans each workload image and manifest, checks RBAC and control-plane component versions, and by default runs a node-collector job on every node. --report summary and namespace or kind filters keep the output readable.

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