Trivy Tutorial: Scan Containers in 12 Steps, 30 Min [2026]

A single unpatched dependency inside a container image is now one of the most common ways attackers get their first foothold in production. Trivy, the open-source security scanner from Aqua Security, exists to catch those problems before they ship. It is a single Go binary that finds known vulnerabilities, misconfigurations, exposed secrets, and license issues across container images, filesystems, Git repositories, Kubernetes clusters, and infrastructure-as-code. This Trivy tutorial walks you through 12 hands-on steps, from your first scan to a CI/CD gate and a continuously scanned Kubernetes cluster, in roughly 30 minutes.

This tutorial was originally built against Trivy v0.71.0 (released June 1, 2026), though the install steps always pull the latest build regardless – Aqua Security has since tagged v0.74.0 as the newest release on GitHub on August 14, 2026, and the commands below work unchanged against it. The project carries an Apache-2.0 license and more than 36,000 GitHub stars, making it the most popular open-source scanner of its kind. Updated September 2026.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What Trivy Is and What It Finds in 2026

Trivy started life as a container image vulnerability scanner and has grown into an all-in-one security tool. In 2026 a single trivy command can inspect eight different target types, and every scan runs locally against a vulnerability database that Trivy downloads and caches for you. There is no agent to install, no server to stand up, and no account to create. You point the binary at a target, and it returns a report you can read in a terminal or feed into a pipeline.

Under the hood, a Trivy scan combines several data sources. Operating-system package vulnerabilities come from distribution security trackers (Alpine, Debian, Ubuntu, Red Hat, SUSE, Amazon Linux, and more). Application dependency vulnerabilities come from the GitHub Security Advisory Database, the National Vulnerability Database (NVD), and language-specific advisories. All of this is packaged into the trivy-db artifact, distributed as an OCI image and refreshed roughly every six hours, so your local copy stays current without any manual updates.

Here is what a single Trivy install can scan today:

  • Container images – OS packages and application dependencies inside any Docker or OCI image, local or in a registry.
  • Filesystems and projects – lock files such as package-lock.json, requirements.txt, go.sum, and Cargo.lock.
  • Git repositories – scan a remote repo by URL without cloning it yourself.
  • Infrastructure-as-code – Terraform, CloudFormation, Dockerfiles, Kubernetes manifests, Helm charts, and ARM templates for misconfigurations.
  • Secrets – hardcoded API keys, tokens, and private keys via built-in rules.
  • Kubernetes clusters – running workloads, node components, and RBAC via trivy k8s or the Trivy Operator.
  • SBOMs – generate or scan a Software Bill of Materials in CycloneDX or SPDX format.
  • Licenses – flag risky or non-compliant open-source licenses in your dependencies.

That breadth is the whole point. Instead of stitching together a separate tool for image scanning, another for IaC, and a third for secrets, one binary and one report cover the entire software supply chain. Supply-chain attacks are not hypothetical either – high-profile incidents such as the ShinyHunters Oracle zero-day campaign show why teams now scan every layer, from source code to running pod.

Trivy vs Grype vs Clair: How the Scanners Compare

Before you commit to a vulnerability scanner, it helps to know where Trivy sits against the other two open-source heavyweights, Anchore’s Grype and Quay’s Clair. All three are free, run in CI, and pull from the same public advisory feeds. The difference is scope and speed, not licensing cost.

ScannerMaintainerGitHub starsScopeBest for
TrivyAqua Security~36,700Images, filesystems, repos, IaC, Kubernetes, secrets, SBOM, licensesAll-in-one DevSecOps scanning
GrypeAnchore~12,500Container images and filesystems (CVEs only), pairs with Syft for SBOMFast, focused CVE scanning
ClairQuay / Red Hat~11,000Container image CVEs via a server + APIRegistry-integrated scanning service

The practical takeaways from independent 2026 comparisons: Grype is a pure CVE scanner that runs roughly 30–40% faster than Trivy on image-only vulnerability scans and has a reputation for low false positives, but it does not touch IaC, Kubernetes, or secrets. Clair runs as a service you call over an API, which suits registry integrations but adds operational overhead and, like Grype, only scans image vulnerabilities. Trivy trades a little raw speed for coverage: one binary handles the whole list above. A pragmatic 2026 setup uses Trivy as the primary all-in-one scanner and, on your most critical external-facing images, adds Grype as a fast second opinion.

For this tutorial we focus entirely on Trivy, because it is the tool that covers the most ground with the least setup. If you already run container tooling, our Docker vs Podman comparison and Docker production-stack tutorial pair naturally with what follows.

Prerequisites and Versions

Trivy is deliberately light on prerequisites. You need a terminal, roughly 2 GB of free disk for the vulnerability database and image cache, and internet access for the first database download. To follow every step, including the container and Kubernetes sections, install the tools in the table below. If you only want to scan code and images, you can stop after Docker.

ComponentVersion used hereWhy you need itRequired?
Trivyv0.71.0 (June 1, 2026)The scanner itselfYes
Operating systemLinux, macOS, or Windows (WSL2)Trivy ships native binaries for all threeYes
Docker or PodmanDocker 27+ / Podman 5+To build and scan container imagesFor image steps
Git2.40+To scan repositories and clone the sample projectRecommended
kubectl + a clusterkubectl 1.30+, kind or a real clusterFor the Kubernetes and Trivy Operator stepsFor Step 10
Helm3.14+Easiest way to install the Trivy OperatorFor Step 10

Disk space is the one prerequisite people forget. The main vulnerability database is around 900 MB uncompressed once downloaded, and the separate Java database adds more if you scan JAR files. Budget a couple of gigabytes and you will never hit a wall mid-scan.

Step 1 – Install Trivy on Any OS

Trivy offers a package for nearly every platform – even openSUSE users get a native option, with SUSE Package Hub shipping Trivy 0.68.2 across four CPU architectures on December 30, 2025. Pick the line that matches your system. All of these pull the latest stable release, so you get v0.74.0 (Aqua Security’s newest tag as of August 14, 2026) or newer automatically. If you set up the APT or RPM repository before April 2026, re-import the signing key: the v0.70.0 release on April 17, 2026 rotated the GPG keys used to sign the deb/rpm packages, and installs pinned to the old key will start failing verification.

# macOS or Linux with Homebrew
brew install trivy

# Debian / Ubuntu (add the Aqua APT repo once)
sudo apt-get install -y wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install -y trivy

# Any Linux/macOS via the official install script
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin

# Docker (no install at all)
docker run --rm aquasec/trivy:latest --version

Windows users on WSL2 should use the Linux instructions; native Windows binaries are also available on the GitHub Releases page. Once installed, confirm the version:

trivy --version
Version: 0.71.0
Vulnerability DB:
  Version: 2
  UpdatedAt: 2026-06-02 06:11:23.482 +0000 UTC
  NextUpdate: 2026-06-02 12:11:23.482 +0000 UTC

If the Vulnerability DB block is missing, that is normal on a fresh install – Trivy downloads the database automatically the first time you run a scan. You can pre-fetch it now with trivy image --download-db-only if you want the first real scan to be fast.

Step 2 – Run Your First Container Image Scan

The fastest way to see Trivy work is to scan a public image. We will use an older Python base image, which reliably contains outdated OS packages so you get a meaningful report. The first run downloads the vulnerability database (this happens once).

trivy image python:3.9-slim

Trivy pulls the image if it is not already local, unpacks each layer, identifies the OS and every installed package, and matches them against the database. Your output will look similar to this (exact counts change as the database updates):

python:3.9-slim (debian 12.5)
============================
Total: 84 (UNKNOWN: 0, LOW: 62, MEDIUM: 14, HIGH: 7, CRITICAL: 1)

Library        Vulnerability   Severity  Status  Installed  Fixed
-------------  --------------  --------  ------  ---------  --------------
libc-bin       CVE-2025-xxxxx  HIGH      fixed   2.36-9     2.36-9+deb12u1
zlib1g         CVE-2025-xxxxx  CRITICAL  fixed   1.2.13-1   1.2.13-1+deb1

Read that top line first: it is your risk summary. The table then lists each vulnerable package, the CVE identifier, its severity, whether a fix exists (Status), the installed version, and the version that resolves it. When Fixed is populated, upgrading that package closes the finding. This single command is the core of Trivy – everything else in this tutorial is a variation on it aimed at a different target.

Step 3 – Read Severities, Exit Codes, and Output Formats

A raw scan of a base image can produce dozens of low-severity findings you will never act on. The skill in using Trivy well is filtering to what matters and turning results into a pass/fail signal. Trivy classifies every finding into one of five severity levels, and you control which ones show up and whether they break your build.

SeverityMeaningTypical CI action
CRITICALRemote code execution or equivalent, trivial to exploitFail the build immediately
HIGHSerious impact, exploitable under common conditionsFail the build
MEDIUMModerate impact or harder to exploitWarn, track, schedule a fix
LOWMinor impact or requires unusual accessLog only
UNKNOWNSeverity not yet rated by any sourceReview manually

To scan only for the severities you care about and to skip vulnerabilities that have no fix yet, combine two flags. The --ignore-unfixed flag is the single biggest noise reducer for most teams, because you cannot act on a vulnerability that has no patch available.

# Show only HIGH and CRITICAL findings that have a fix
trivy image --severity HIGH,CRITICAL --ignore-unfixed python:3.9-slim

# Same scan, but make it fail (exit code 1) so CI can react
trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 python:3.9-slim
echo "Trivy exit code: $?"

By default Trivy returns exit code 0 even when it finds problems – it simply reports. The --exit-code 1 flag flips that behavior so the command fails when any matching vulnerability is found, which is exactly what you want in a pipeline. Trivy also speaks several output formats beyond the default table, so you can hand results to other tools:

# Machine-readable JSON for dashboards or scripts
trivy image --format json -o result.json python:3.9-slim

# SARIF, which GitHub code scanning ingests natively
trivy image --format sarif -o result.sarif python:3.9-slim

Use -o (output) to write to a file instead of the terminal. The JSON format is ideal when you want to post-process results, and SARIF is what you will feed into GitHub’s Security tab in Step 9.

Step 4 – Scan Your Codebase, Filesystem, and Dependencies

You do not need a built image to find vulnerable dependencies. The trivy fs command scans a directory directly, reading lock files to identify exactly which library versions your project pins. This is the fastest feedback loop for developers, because it runs on source code before anything is built or pushed.

# Scan the current project directory for vulnerable dependencies
trivy fs .

# Scan a specific path and only surface actionable findings
trivy fs --severity HIGH,CRITICAL --ignore-unfixed ./my-service

Trivy recognizes lock files for most major ecosystems: npm and Yarn (package-lock.json, yarn.lock), Python (requirements.txt, poetry.lock), Go (go.mod, go.sum), Rust (Cargo.lock), Ruby (Gemfile.lock), Java (pom.xml and JAR files), PHP (composer.lock), and .NET packages. The v0.71.0 release specifically added and improved .NET vulnerability detection, so C# projects now get first-class coverage.

You can also scan a remote Git repository without cloning it yourself, which is handy for auditing an open-source dependency or a teammate’s branch:

trivy repo https://github.com/your-org/your-service

Because trivy fs reads lock files, the accuracy of its report depends on those files being committed and up to date. A project that pins dependencies loosely (for example, a requirements.txt with only package names and no versions) gives Trivy less to work with. Commit your lock files – it is good practice anyway.

Step 5 – Detect Hardcoded Secrets Before They Ship

Secret scanning is enabled by default in Trivy for image, filesystem, and repository scans, so you may already have seen secret findings in earlier steps. Trivy ships with a built-in ruleset that recognizes common credential patterns: AWS access keys, GitHub tokens, GCP service-account keys, Slack tokens, private SSH keys, and generic high-entropy strings. It scans the actual file contents, so it catches secrets baked into image layers as well as those sitting in your source tree.

To run a scan focused only on secrets, use the --scanners flag:

# Only look for secrets in the current directory
trivy fs --scanners secret .

A finding looks like this, with the file, the rule that matched, and the exact line, with the secret itself redacted so it is not printed to your logs:

config/settings.py (secrets)
============================
Total: 1 (HIGH: 1)

HIGH: AWS (aws-access-key-id)
Access key exposed in source code
config/settings.py:14
   14 [ AWS_ACCESS_KEY_ID = "AKIA********************" ]

The most valuable place to run this is on container images. Developers frequently copy an entire project directory into an image with COPY . ., accidentally baking a local .env file or credentials into a layer that then gets pushed to a registry. A quick trivy image --scanners secret your-image:tag catches exactly that class of mistake. Pair it with host-level defenses like Fail2ban and you close two of the most common attack paths at once.

Step 6 – Scan Infrastructure-as-Code and Dockerfiles

Vulnerable dependencies are only half the risk. The other half is misconfiguration: an S3 bucket left public, a container that runs as root, a security group open to the world. Trivy’s config command (also reachable as trivy misconfig) scans infrastructure-as-code against hundreds of built-in policies written in Rego, the Open Policy Agent language.

# Scan a directory of Terraform, Dockerfiles, and Kubernetes manifests
trivy config .

# Fail the build on HIGH and CRITICAL misconfigurations only
trivy config --severity HIGH,CRITICAL --exit-code 1 ./infra

Trivy understands Terraform and Terraform plans, CloudFormation, Dockerfiles, Kubernetes and Helm manifests, and Azure ARM templates. A Dockerfile scan, for example, flags images that run as root, use the latest tag, or expose unnecessary ports. Here is a representative misconfiguration finding for a Dockerfile:

Dockerfile (dockerfile)
=======================
Tests: 26 (SUCCESSES: 24, FAILURES: 2)
Failures: 2 (MEDIUM: 1, HIGH: 1)

HIGH: Specify at least 1 USER command with non-root user
Running containers as root is a significant security risk.
See https://avd.aquasec.com/misconfig/ds002
Dockerfile:1-9

Each finding links to Aqua’s vulnerability database (AVD) with an explanation and a remediation. If you manage cloud infrastructure with Terraform or its open-source fork, this step slots directly into that workflow – our OpenTofu vs Terraform vs Pulumi comparison covers the tooling landscape, and Trivy scans all three.

Step 7 – Generate a Software Bill of Materials (SBOM)

A Software Bill of Materials is a machine-readable inventory of every component in your software. Regulators and enterprise customers increasingly require one, and it is the foundation for answering the question every security team dreads during an incident: are we affected by this new CVE? Trivy generates an SBOM from any image or filesystem in the two dominant standard formats, CycloneDX and SPDX.

# Generate a CycloneDX SBOM (Trivy v0.71.0 supports CycloneDX 1.6)
trivy image --format cyclonedx -o sbom.cdx.json python:3.9-slim

# Generate an SPDX SBOM in JSON
trivy image --format spdx-json -o sbom.spdx.json python:3.9-slim

The real power comes from the reverse operation: once you have an SBOM, you can re-scan it later without re-analyzing the image. When a new critical CVE lands, you scan your stored SBOMs to instantly know which artifacts are affected.

# Scan a previously generated SBOM for vulnerabilities
trivy sbom sbom.cdx.json

This SBOM-first workflow is where supply-chain security is heading in 2026. Generate an SBOM at build time, store it as a build artifact alongside the image, and you have a permanent, queryable record of what shipped. The v0.70.0 release added CVSS v4 scoring inside CycloneDX reports, so the SBOMs Trivy produces now carry richer severity data than they did a year ago.

Step 8 – Build the Complete Working Project: Scan a Vulnerable Flask App

Now we tie the pieces together with a small but complete project: a Python Flask service with deliberately outdated dependencies and a sloppy Dockerfile. Scanning it end to end demonstrates vulnerability, secret, and misconfiguration detection in one realistic codebase. Create a directory and add these three files.

First, requirements.txt with pinned, known-vulnerable versions:

# requirements.txt
Flask==2.0.1
requests==2.19.1
PyYAML==5.3.1
Jinja2==2.11.2

Next, a minimal app.py. Note the hardcoded key on purpose – Trivy’s secret scanner should catch it:

# app.py
from flask import Flask

app = Flask(__name__)
API_KEY = "AKIAIOSFODNN7EXAMPLE"  # never do this in real code

@app.route("/")
def home():
    return "Trivy tutorial demo service"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

Finally, a Dockerfile that runs as root and uses a floating base tag – both misconfigurations Trivy will flag:

# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["python", "app.py"]

Now run the full trivy scan matrix against the project. First the source tree, which catches the dependencies and the hardcoded key; then the IaC scan for the Dockerfile; then build the image and scan the finished artifact:

# 1. Dependencies + secrets in the source tree
trivy fs --scanners vuln,secret .

# 2. Dockerfile misconfigurations
trivy config .

# 3. Build the image, then scan the built artifact
docker build -t trivy-demo:latest .
trivy image --scanners vuln,secret,misconfig trivy-demo:latest

The filesystem scan reports vulnerabilities in Flask, requests, PyYAML, and Jinja2 (PyYAML 5.3.1, for instance, is affected by the well-known CVE-2020-14343 arbitrary-code-execution issue, fixed in 5.4), plus the AWS key finding. The config scan flags the missing non-root USER instruction. The image scan combines the Debian OS package findings with everything above. In under a minute you have a full picture of the project’s risk – the exact workflow you will now automate in CI. To learn how to harden the container build itself, our Docker production-stack tutorial is a good companion.

Step 9 – Gate Your CI/CD Pipeline with GitHub Actions and SARIF

Scanning locally is useful, but the real payoff is an automated gate that scans every pull request and blocks merges that introduce critical vulnerabilities. Aqua maintains an official GitHub Action, aquasecurity/trivy-action, whose latest release is v0.36.0 – pin to it deliberately, because this is not a hypothetical risk: Aqua Security’s own advisory AV26-283 disclosed that a malicious Trivy v0.69.4 build, alongside tampered Docker images v0.69.5–0.69.6, went out in March 2026, and StepSecurity later dated the poisoned release to March 19, 2026 and traced it to compromised release automation that had tampered 76 of the action’s 77 published tags. Phoenix Security had already flagged v0.69.3 as the last known-safe version on March 3, 2026, and when Aqua Security discussed the incident publicly on March 20, 2026 it urged teams to pin to Trivy v0.69.3, trivy-action v0.35.0, and setup-trivy v0.2.6; a BSI advisory issued in August 2026 later reconfirmed 0.69.2–0.69.3 as the safe version range once the investigation closed. It remains the textbook argument for never trusting a floating tag in a security-scanning step. The workflow below scans the built image, uploads results to GitHub’s Security tab as SARIF, and fails the job on High or Critical findings.

# .github/workflows/trivy.yml
name: Trivy Security Scan
on:
  pull_request:
  push:
    branches: [ main ]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write   # required to upload SARIF
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t trivy-demo:test .

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/[email protected]   # pin to the latest release tag
        with:
          image-ref: trivy-demo:test
          format: sarif
          output: trivy-results.sarif
          severity: HIGH,CRITICAL
          ignore-unfixed: true

      - name: Upload results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: trivy-results.sarif

To make the job actually block a merge on findings rather than just report them, add a second scan step that uses exit-code: '1'. A common pattern is to run one step that uploads SARIF for visibility (with if: always()) and a second gating step that fails the build:

      - name: Fail on High/Critical
        uses: aquasecurity/[email protected]
        with:
          image-ref: trivy-demo:test
          format: table
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          exit-code: '1'

If you prefer not to depend on a third-party action, you can install the Trivy binary in the runner with the same official install script from Step 1 and call it directly – this is fully version-agnostic and works in any CI system, including GitLab CI, CircleCI, and Jenkins. GitLab users get an even easier path: Trivy ships a ready-made GitLab CI template you can include in your pipeline.

Step 10 – Continuous Kubernetes Scanning with the Trivy Operator

Scanning at build time catches problems before deployment, but images that were clean at build can become vulnerable later as new CVEs are disclosed. The Trivy Operator solves this by running inside your cluster and continuously scanning workloads, storing results as native Kubernetes custom resources. It is a separate project (around 1,900 GitHub stars) that builds on the same scanning engine and ships its own release cadence – Akamai’s App Platform v4.11.0, for instance, bumped its bundled Operator from 0.57.1 to 0.65.0 on September 22, 2025. Keep the Operator itself current, too: version 0.64.1 shipped August 19, 2025 specifically to fix CVE-2025-53547, a code-execution flaw in its own Helm chart.

Install it with Helm into its own namespace:

helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator \
  --namespace trivy-system \
  --create-namespace

Once running, the operator automatically scans every workload in the cluster and writes a VulnerabilityReport for each. You query them like any other Kubernetes resource:

# List vulnerability reports across all namespaces
kubectl get vulnerabilityreports -A

# See the misconfiguration audit for your workloads
kubectl get configauditreports -A

# Drill into one report
kubectl describe vulnerabilityreport -n default my-report-name

Because the results are stored as CRDs, they integrate with anything that speaks the Kubernetes API – dashboards, Prometheus exporters, and admission controllers. If you are still standing up your cluster, our Kubernetes cluster tutorial gets you to a working environment where the operator can run. For one-off scans without installing anything, trivy k8s --report summary cluster scans a cluster directly from your workstation.

Step 11 – Suppress False Positives with .trivyignore and VEX

No scanner is perfect, and every team eventually hits a vulnerability that does not apply to them – a CVE in a code path they never call, or one their platform already mitigates. Silencing these correctly is what keeps a scan trustworthy. Trivy gives you two mechanisms, from simple to sophisticated.

The simplest is a .trivyignore file in your project root. List the CVE IDs to suppress, one per line, ideally with a comment explaining why and an expiry reminder:

# .trivyignore
# Not exploitable: the vulnerable function is never called. Review 2026-09.
CVE-2025-12345

# Accepted risk, mitigated at the network layer. Review 2026-09.
CVE-2025-67890

The more rigorous, auditable approach is VEX (Vulnerability Exploitability eXchange), an open standard for declaring whether a product is actually affected by a given vulnerability. Trivy supports OpenVEX and CycloneDX VEX documents. Instead of a blunt ignore list, a VEX statement records a justification such as “vulnerable_code_not_in_execute_path” that other tools can read and trust. You attach it at scan time:

trivy image --vex ./my-app.openvex.json trivy-demo:latest

The v0.71.0 release fixed VEX document loading from within the repository directory, making this workflow smoother. For teams under compliance pressure, VEX is the difference between an unexplained suppression and a documented, defensible risk decision. Use .trivyignore for quick local suppressions and VEX for anything that needs an audit trail.

Step 12 – Scale Scans with Caching and Client/Server Mode

The final step is about speed at scale. Two things dominate Trivy’s runtime: downloading the vulnerability database and analyzing image layers. In a CI fleet running hundreds of jobs, every runner re-downloading the ~900 MB database is wasteful and can trip rate limits. Trivy solves this with a client/server architecture.

Run one Trivy server that holds the database, then point lightweight clients at it. The clients never download the database themselves – they send the target to the server and get results back:

# On the server host
trivy server --listen 0.0.0.0:4954

# On each client / CI runner
trivy image --server http://trivy-server:4954 trivy-demo:latest

For pipelines that cannot use a server, cache the database as a CI artifact between runs, or self-host a mirror of the trivy-db OCI image in your own registry and point Trivy at it with the --db-repository flag. This also insulates you from public registry rate limits. A few more performance levers worth knowing:

  • --scanners vuln – disable secret and misconfig scanning when you only need CVEs, for a faster run.
  • --skip-db-update – reuse the cached database and skip the update check when you scan repeatedly in a short window.
  • --cache-dir – point the cache at a persistent volume so it survives between CI jobs.
  • --parallel – increase the number of images scanned concurrently in batch runs.

With those in place, a full trivy scan in CI drops from tens of seconds of database work to a few seconds of pure analysis. That is the setup mature teams run in production, and it is where this tutorial’s 12 steps have been leading.

5 Common Trivy Pitfalls to Avoid

These are the mistakes that most often turn a promising Trivy rollout into ignored, noisy output. Avoid them and your scans stay trusted.

  • Scanning without --ignore-unfixed and drowning in noise. A base image can report dozens of vulnerabilities that have no available patch. Developers quickly learn to ignore a red report that never turns green. Filter to fixable, high-severity findings first, then expand.
  • Forgetting --exit-code 1 in CI. Trivy’s default exit code is 0 even when it finds critical issues. If you forget this flag, your pipeline reports vulnerabilities but happily merges anyway. The gate does nothing.
  • Pinning the GitHub Action to a moving branch. Referencing @master means an upstream change can silently alter your pipeline’s behavior. Always pin aquasecurity/trivy-action to a specific release tag such as @0.36.0.
  • Not committing lock files. A trivy fs scan is only as accurate as the lock files it reads. If package-lock.json or poetry.lock is gitignored, Trivy sees far less of your dependency tree.
  • Blanket-ignoring CVEs with no expiry. A .trivyignore that grows forever becomes a place where real risk hides. Add a comment and a review date to every entry, and audit the file quarterly.

Troubleshooting: 8 Common Trivy Errors and Fixes

When a Trivy scan misbehaves, it is almost always one of these eight issues. Each has a quick fix.

  • “failed to download vulnerability DB” / TOOMANYREQUESTS. The public registry rate-limited you. Authenticate to GitHub Container Registry, cache the database between runs, or mirror trivy-db in your own registry with --db-repository.
  • Scan returns 0 vulnerabilities on an image you know is old. The database probably failed to load. Run trivy image --download-db-only and check the output of trivy --version for a valid DB timestamp.
  • “unable to find the specified image” for a local build. Trivy could not reach your Docker daemon. Confirm Docker is running, or export the image to a tar with docker save and scan it with trivy image --input image.tar.
  • Java or JAR files show no findings. The separate Java database was not downloaded. Ensure network access on the first Java scan, or pre-fetch with trivy image --download-java-db-only.
  • CI job passes despite critical findings. You are missing --exit-code 1 (CLI) or exit-code: '1' (Action). Add it to the gating step.
  • Scan is painfully slow on every run. The database is being re-downloaded each time. Persist the cache directory with --cache-dir on a shared volume, or move to client/server mode from Step 12.
  • Out-of-memory or disk-full errors on large images. Very large images need headroom. Free disk space for the cache, or scan a generated SBOM instead of the full image with trivy sbom.
  • SARIF upload rejected by GitHub. The job lacks permission. Add security-events: write to the workflow’s permissions block, as shown in Step 9.

Advanced Tips for Production DevSecOps

Once the basics are running, these practices separate a checkbox scan from a security program that actually reduces risk.

  • Scan in three places, not one. Run trivy fs in the developer’s pre-commit hook, trivy image in CI, and the Trivy Operator in the cluster. Each catches issues the others miss because they run at different times.
  • Use custom policies. Trivy’s misconfiguration engine accepts your own Rego policies, so you can enforce organization-specific rules (required labels, banned base images) alongside the built-in checks.
  • Feed results into a SIEM. JSON output from Trivy flows naturally into a security data pipeline. Correlating build-time findings with runtime alerts in a tool like Wazuh gives you a single view of risk.
  • Sign and attest your SBOMs. Combine Trivy’s SBOM output with Cosign to produce signed attestations, so consumers of your images can verify both what is inside and that the inventory is authentic.
  • Track findings over time. Store JSON reports as build artifacts and graph the count of High/Critical findings per release. A downward trend is the metric that proves the program works.

Supply-chain incidents keep making headlines – from ransomware crews like The Gentlemen to nation-state dependency attacks – and the common thread is a component nobody was watching. Continuous scanning with Trivy is how you make sure that component is not yours.

Related Coverage

Frequently Asked Questions

Is Trivy free to use?

Yes. Trivy is fully open source under the Apache-2.0 license and free for both personal and commercial use, including in CI/CD and Kubernetes. Aqua Security, which maintains it, sells a commercial platform with additional management and reporting features, but the Trivy scanner itself has no paywalled functionality for the workflows in this tutorial.

What is the latest version of Trivy?

As of September 2026, the newest tag in Aqua Security’s GitHub repository is Trivy v0.74.0, published August 14, 2026, superseding the v0.71.0 release from June 1, 2026 that first added .NET vulnerability detection and CycloneDX 1.6 support. Trivy releases on a roughly monthly cadence – Safeguard’s release tracking shows the run from v0.59.0 on January 30, 2025 through v0.69.1 on October 28, 2025 alone covered ten releases in nine months – so always install the latest build from the official repositories rather than pinning an old version.

Trivy vs Grype – which should I use?

Use Trivy if you want one tool for images, code, IaC, Kubernetes, and secrets. Use Grype if you want the fastest possible pure CVE scan and are happy to add separate tools for everything else. Grype is roughly 30–40% faster on image-only vulnerability scans, but Trivy’s broader coverage means most teams standardize on it and reach for Grype only as a second opinion on critical images.

Does Trivy scan for secrets and misconfigurations, or just CVEs?

All three. Vulnerability and secret scanning are enabled by default for image, filesystem, and repository targets. Misconfiguration scanning of infrastructure-as-code runs through trivy config, and license scanning is available with --scanners license. This all-in-one coverage is Trivy’s main advantage over single-purpose scanners.

How do I make Trivy fail my CI build on vulnerabilities?

Add --exit-code 1 to the CLI, or exit-code: '1' to the GitHub Action, combined with --severity HIGH,CRITICAL to scope the gate. By default Trivy exits 0 and only reports, so without this flag your pipeline will pass even when critical vulnerabilities are present.

Where does Trivy get its vulnerability data?

Trivy combines OS distribution security trackers, the GitHub Security Advisory Database, the NVD, and language-specific advisories into the trivy-db artifact, which is distributed as an OCI image and refreshed roughly every six hours. Your local copy updates automatically on scan, so findings stay current without manual intervention.

Can Trivy generate an SBOM?

Yes. Trivy generates a Software Bill of Materials from any image or filesystem in CycloneDX and SPDX formats using --format cyclonedx or --format spdx-json. You can also scan an existing SBOM with trivy sbom, which lets you re-check stored inventories against new CVEs without re-analyzing the original artifact.

Does Trivy work with Kubernetes?

Yes, two ways. The trivy k8s command scans a cluster on demand from your workstation, and the Trivy Operator runs inside the cluster to scan workloads continuously, storing results as native Kubernetes custom resources such as VulnerabilityReport. The operator is the recommended approach for ongoing production monitoring.

The Bottom Line

Trivy earns its place as the default open-source security scanner in 2026 by doing the whole job with one binary: it finds vulnerabilities, secrets, and misconfigurations across images, code, IaC, and Kubernetes, generates SBOMs, and drops cleanly into any CI/CD pipeline. Start with a single trivy image scan today, add an --exit-code 1 gate to your pipeline this week, and install the Trivy Operator when you are ready for continuous coverage. Each of these 12 steps stands on its own, and together they turn scanning from an afterthought into a habit – which is exactly what modern supply-chain security requires. You can dig deeper in the official Trivy documentation, the Trivy GitHub repository, and the standards it builds on: CycloneDX, SPDX, and OpenVEX. For more hands-on security guides, browse our cybersecurity coverage.

Sofia Lindström

Sofia Lindström

Editor-in-Chief

Sofia Lindström is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles