How do you scan container images for vulnerabilities using Trivy?
Quick Answer
You scan container images by running trivy image followed by the image name and tag. Trivy automatically downloads the vulnerability database, pulls or accesses the image layers, identifies OS and application packages, and reports any known CVEs with their severity levels.
Detailed Answer
Scanning a container image with Trivy is like putting a package through an airport X-ray machine. The machine looks inside every layer, identifies all the contents, and flags anything suspicious. Similarly, Trivy unpacks each layer of a Docker image, inventories all installed packages and dependencies, and checks each one against a database of known vulnerabilities.
The basic command is trivy image followed by the image reference. Trivy can scan images from multiple sources: local images built with Docker (trivy image payments-api:latest), remote images from registries like Docker Hub or ECR (trivy image registry.company.com/order-processing-service:v1.3.0), and even OCI image archives saved as tar files (trivy image --input image.tar). When scanning a local image, Trivy communicates with the Docker daemon to access image layers. For remote images, Trivy pulls the layers directly from the registry without requiring Docker to be installed, which is useful in CI environments that use tools like Kaniko or Buildah instead of Docker.
Internally, Trivy performs two passes when scanning a container image. The first pass identifies the operating system distribution (Debian, Alpine, Amazon Linux, etc.) and all OS-level packages installed via the package manager. The second pass detects application-level dependencies by looking for lock files and manifest files within the image layers. For example, it finds package-lock.json for Node.js, requirements.txt or Pipfile.lock for Python, go.sum for Go, and pom.xml or build.gradle for Java. Each discovered package is cross-referenced against Trivy's vulnerability database, which aggregates data from sources like the National Vulnerability Database (NVD), distribution-specific advisories (Debian Security Tracker, Alpine SecDB), and language-specific advisory databases (GitHub Advisory Database, RustSec).
In production CI/CD pipelines, teams typically run Trivy image scanning as a build step after the Docker image is built but before it is pushed to the registry. For a service like checkout-service, the pipeline builds the image, runs trivy image with --exit-code 1 and --severity CRITICAL,HIGH flags, and only pushes the image to the registry if Trivy exits successfully. This prevents vulnerable images from ever reaching production. Teams often use the --ignore-unfixed flag to suppress vulnerabilities that have no available patch, reducing noise in the results. Registry-side scanning is also common: services like Amazon ECR, Google Artifact Registry, and Harbor can integrate Trivy to scan images on push.
A key gotcha for beginners is understanding image layers and caching. If your Dockerfile installs packages in an early layer and that layer is cached, rebuilding the image may not pull the latest security patches even though you ran apt-get update. Trivy will flag these outdated packages. The fix is to ensure your base image is regularly updated and that package installation layers are not aggressively cached. Another common issue is scanning multi-stage build images: Trivy only scans the final image, not intermediate build stages, so vulnerable build tools in earlier stages will not appear in the report as long as they are not copied to the final image.