Containerized applications are a cornerstone of modern software development, offering portability and scalability. However, this agility introduces new security challenges. Manually scanning every container image for vulnerabilities is impractical and prone to error, especially in fast-paced development environments. Failing to identify and remediate these vulnerabilities early can lead to significant security breaches, compliance failures, and costly fixes later in the development lifecycle.
This guide provides a practical, step-by-step approach to integrating automated container security scanning into your CI/CD pipelines using Trivy. You'll learn how to set up Trivy in popular CI/CD platforms like GitHub Actions and GitLab CI, interpret its reports, and establish policies to prevent vulnerable images from being deployed. By the end, you'll be able to implement reliable, automated security checks that enhance your application's security posture without slowing down your development process.
What You'll Learn
- The importance of integrating container security scanning into CI/CD.
- How Trivy works and why it's a suitable tool for automated scanning.
- Step-by-step instructions for integrating Trivy with GitHub Actions.
- Step-by-step instructions for integrating Trivy with GitLab CI.
- Methods for interpreting Trivy scan reports and setting failure policies.
- Best practices for maintaining an effective container security scanning strategy.
Why Automate Container Security Scanning?
In modern DevOps practices, container images are built and deployed frequently. Each image often contains numerous dependencies, libraries, and operating system packages, any of which could harbor known vulnerabilities. Manual checks are simply not feasible when dozens or hundreds of images are pushed daily.
Automating container security scanning directly within your CI/CD pipeline offers several critical advantages:
- Early Detection: Vulnerabilities are identified at the earliest possible stage—during the build process—before they reach staging or production environments. This adherence to the "shift-left" security principle significantly reduces the cost and effort of remediation.
- Consistency: Automated scans ensure that every container image undergoes the same security checks, eliminating human error and ensuring consistent security standards across all your projects.
- Speed: Integrated scans run automatically with each code commit or image build, providing rapid feedback to developers without manual intervention, thus maintaining development velocity.
- Compliance: Many regulatory frameworks require regular vulnerability assessments. Automated scanning helps maintain continuous compliance by providing auditable records of security checks.
- Prevention: By configuring pipelines to fail builds containing critical vulnerabilities, you can prevent insecure images from ever being deployed, reinforcing your security posture.
Introducing Trivy: Your Vulnerability Scanner
Trivy is an open-source, comprehensive, and easy-to-use vulnerability scanner for containers and other artifacts. Developed by Aqua Security, it's known for its speed and accuracy, making it an excellent choice for integration into CI/CD pipelines. Trivy can scan:
- Container Images: Scans operating system packages (e.g., Alpine, Debian, CentOS) and application dependencies (e.g., npm, pip, composer, yarn, cargo, go.mod).
- Filesystems: Can scan local directories.
- Git Repositories: Directly scans repository contents.
- Kubernetes Clusters: Scans running workloads for misconfigurations and vulnerabilities.
- Cloud Infrastructure: Scans AWS, Azure, and GCP for misconfigurations.
- Infrastructure as Code (IaC): Scans Terraform, CloudFormation, Kubernetes, and other configuration files for misconfigurations.
For container image scanning, Trivy fetches vulnerability information from multiple sources, including the National Vulnerability Database (NVD) and various Linux distribution-specific security advisories, providing a comprehensive view of potential risks.
Pro Tip: Trivy performs a deep scan, analyzing both OS packages and application dependencies within your container image. This dual-layer approach provides a more complete security assessment compared to tools that only focus on one aspect.
Integrating Trivy with GitHub Actions
GitHub Actions is a popular CI/CD platform integrated directly into GitHub repositories. It allows you to automate workflows, including building, testing, and deploying your code. Integrating Trivy into a GitHub Actions workflow is straightforward.
Setting Up the Workflow
GitHub Actions workflows are defined in YAML files (e.g., .github/workflows/main.yml) within your repository. A typical workflow for container security scanning will involve steps to check out your code, build your Docker image, and then scan it with Trivy.
Configuring Trivy Scan Parameters
When running Trivy, you can specify various parameters to control the scan's behavior and output:
--severity: Filter vulnerabilities by severity level (e.g.,UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL).--exit-code: Set a non-zero exit code if vulnerabilities are found, causing the CI/CD pipeline to fail. For example,--exit-code 1will fail the job if any vulnerability is detected.--format: Specify the output format (e.g.,table,json,sarif). SARIF format is particularly useful for integrating with GitHub's security features.--ignore-unfixed: Only report vulnerabilities for which a fix is available.--vuln-type: Specify vulnerability types to scan (e.g.,os,library).
Example GitHub Actions Workflow
This example workflow builds a Docker image, scans it with Trivy, and uploads the SARIF report to GitHub Security tab.
name: Container Security Scan
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub (optional, if pushing to a private registry)
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
push: false # Do not push to registry yet
tags: myapp:latest
load: true # Load image to Docker daemon for scanning
- name: Run Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:latest'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
exit-code: '1' # Fail the build if HIGH or CRITICAL vulnerabilities are found
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
category: 'Trivy' # Category to display in GitHub Security tab
In this workflow:
- The
docker/build-push-actionbuilds the image and usesload: trueto make it available to the local Docker daemon where Trivy will run. aquasecurity/trivy-action@masteris a convenient GitHub Action for running Trivy.severity: 'HIGH,CRITICAL'ensures only high and critical vulnerabilities are reported.exit-code: '1'makes the job fail if any vulnerabilities of the specified severity are found.github/codeql-action/upload-sarif@v3uploads the SARIF report, making the results visible in your repository's Security tab under "Code scanning alerts."
Integrating Trivy with GitLab CI
GitLab CI/CD is another powerful integrated CI/CD platform. Workflows are defined in a .gitlab-ci.yml file in the root of your repository. GitLab CI uses Docker images to execute jobs, which simplifies running Trivy.
GitLab CI Configuration
To integrate Trivy, you'll typically define a job that:
- Uses a Docker-enabled runner.
- Builds your container image (if not already built in a previous stage).
- Pulls the Trivy Docker image or installs Trivy directly.
- Executes the Trivy scan command against your built image.
- Stores the scan results as an artifact.
Example GitLab CI YAML
This example .gitlab-ci.yml demonstrates building an image and then scanning it with Trivy in a separate stage.
stages:
- build
- scan
variables:
DOCKER_IMAGE_NAME: myapp
DOCKER_IMAGE_TAG: latest
build_image:
stage: build
image: docker:latest
services:
- docker:dind # Docker in Docker for building images
script:
- docker build -t ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} .
- docker save ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} > image.tar # Save image for scanning stage
artifacts:
paths:
- image.tar # Make the image available to subsequent stages
scan_image:
stage: scan
image: docker:latest # Using Docker image to run Trivy
services:
- docker:dind
script:
- docker load -i image.tar # Load the image from the previous stage
# Install Trivy
- wget https://github.com/aquasecurity/trivy/releases/download/v0.47.0/trivy_0.47.0_Linux-64bit.deb
- sudo dpkg -i trivy_0.47.0_Linux-64bit.deb
# Run Trivy scan
- trivy image --format json --output trivy-results.json --severity HIGH,CRITICAL --exit-code 1 ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} || exit_code=$?
- if [ "$exit_code" -ne 0 ]; then echo "Trivy found vulnerabilities!"; exit $exit_code; fi
artifacts:
paths:
- trivy-results.json
expire_in: 1 week
allow_failure: false # Ensure the pipeline fails if Trivy finds critical issues
In this GitLab CI example:
- The
build_imagejob builds the Docker image and saves it as a.tarfile. This.tarfile is then declared as an artifact, making it accessible to the next stage. - The
scan_imagejob loads the previously built image from the artifact. - Trivy is installed by directly downloading the Debian package. Alternatively, you could use a custom Docker image that already has Trivy installed.
trivy image --format json --output trivy-results.json --severity HIGH,CRITICAL --exit-code 1runs the scan. The--exit-code 1parameter ensures that if any HIGH or CRITICAL vulnerabilities are found, Trivy exits with a non-zero status, causing the GitLab CI job to fail.- The
if [ "$exit_code" -ne 0 ]; then ... fiblock explicitly fails the job if Trivy reports vulnerabilities. - The
trivy-results.jsonfile is saved as an artifact for later review. allow_failure: falseensures the pipeline stops if this job fails.
Pro Tip: For large images, downloading the Trivy database every time can add overhead. Consider using a Trivy air-gapped environment setup or caching the database in your CI/CD environment to speed up scans.
Interpreting Trivy Reports and Setting Failure Policies
Simply running a scan isn't enough; you need to understand the results and act upon them. Trivy provides detailed reports that help you prioritize and remediate vulnerabilities.
Understanding Trivy Output
Trivy's default output (table format) is human-readable and provides key information:
- Vulnerability ID: A unique identifier (e.g., CVE-2023-1234).
- Package: The affected software package.
- Installed Version: The version of the package found in your image.
- Fixed Version: The version of the package where the vulnerability is patched (if available).
- Severity: UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL.
- Title/Description: A brief summary of the vulnerability.
When using json or sarif format, the output is machine-readable, making it suitable for integration with other tools, dashboards, or for automated parsing to trigger actions.
Defining Failure Thresholds
A critical aspect of automation is deciding when a scan result should fail the build. This is where the --exit-code parameter becomes invaluable. Common strategies include:
- Fail on CRITICAL vulnerabilities: This is a strong baseline, preventing the most severe risks from progressing.
- Fail on HIGH and CRITICAL vulnerabilities: A more stringent policy that catches a broader range of significant issues.
- Fail on MEDIUM, HIGH, and CRITICAL vulnerabilities: This can be very strict and might require more frequent review of findings, but offers higher security.
The choice depends on your organization's risk tolerance, compliance requirements, and the maturity of your security practices. Start with a stricter policy and relax it only if necessary, with clear justifications.
Handling False Positives and Exceptions
No scanner is perfect, and sometimes Trivy might report vulnerabilities that are not exploitable in your specific context (false positives) or that you have a documented reason to accept (known risks). Trivy offers mechanisms to manage these:
.trivyignore: You can create a.trivyignorefile in your repository to specify CVE IDs or package names to ignore. This is useful for known false positives or vulnerabilities that are not applicable to your environment.- Vulnerability Exceptions: For more complex scenarios, Trivy supports Vulnerability Exceptions, allowing you to define policies in a YAML file that specify CVEs, severities, or package names to ignore under certain conditions. This provides more granular control and better documentation for your exceptions.
When ignoring vulnerabilities, always document the reason. This ensures transparency and helps during security audits.
Best Practices for Effective Container Security Scanning
To maximize the benefits of automated container security scanning with Trivy, consider these best practices:
- Scan Early and Often: Integrate scans into every build and pull request. The earlier you find a vulnerability, the cheaper and easier it is to fix.
- Use Minimal Base Images: Choose small, purpose-built base images like Alpine Linux or Distroless. They have fewer packages, which translates to a smaller attack surface and fewer potential vulnerabilities.
- Pin Dependency Versions: Explicitly declare and pin the versions of all application dependencies in your Dockerfiles and package manifests. This prevents unexpected vulnerabilities from being introduced by upstream changes.
- Regularly Rebuild Images: Even if your application code hasn't changed, underlying base images and dependencies might have new vulnerabilities or fixes. Regularly rebuild your images to pull in the latest patched versions.
- Monitor for New Vulnerabilities: Trivy's database is constantly updated. For images already in production, consider scheduled scans or using tools that continuously monitor running containers against newly disclosed CVEs.
- Educate Developers: Train your development team on common container security pitfalls, how to interpret Trivy reports, and the importance of addressing security findings promptly.
- Integrate with Notifications: Configure your CI/CD pipeline to send notifications (e.g., Slack, email) when a security scan fails, alerting the relevant teams immediately.
- Automate Remediation (where possible): While not always feasible for complex vulnerabilities, for simple dependency updates, consider automated pull requests to update vulnerable packages.
Comparison: Trivy vs. Other Scanners
Trivy is an excellent tool, but it's part of a broader ecosystem of container security scanners. Understanding its position relative to others can help you make informed decisions.
| Feature/Tool | Trivy | Clair | Docker Scout (formerly Snyk integration) | Aqua Security CSP (Commercial) |
|---|---|---|---|---|
| Primary Use Case | Vulnerability scanning for container images, filesystems, Git repos, IaC, Kubernetes, cloud config. | Vulnerability analysis for container images. Focus on layer-by-layer scanning. | Software Supply Chain Management, vulnerability scanning, SBOM generation, policy enforcement for Docker images. | Comprehensive Cloud Native Application Protection Platform (CNAPP) including vulnerability management, runtime protection, compliance, and more. |
| Open Source / Commercial | Open Source | Open Source | Freemium (with paid tiers for advanced features and usage) | Commercial |
| Learning Curve | Low (single binary, simple CLI) | Moderate (requires a database, API, and scanner component setup) | Low (integrated with Docker Desktop and Docker Hub, intuitive UI) | Moderate to High (broader platform with many features) |
| Integration with CI/CD | Excellent (CLI, GitHub Action, GitLab CI examples) | Good (API-driven, requires custom integration) | Excellent (Docker Desktop, CLI, CI/CD integrations) | Excellent (dedicated CI/CD plugins and integrations) |
| Scan Speed | Fast (known for quick scans) | Moderate (database-dependent) | Fast | Varies by feature, generally fast for individual scans |
| Vulnerability Database | Multiple sources (NVD, OS vendor advisories, language-specific advisories) | Primarily OS vendor advisories, NVD | Proprietary Snyk vulnerability database, NVD, OS vendor advisories | Proprietary Aqua vulnerability database, NVD, OS vendor advisories |
| SBOM Generation | Yes (SPDX, CycloneDX formats) | No direct SBOM generation | Yes | Yes |
| Runtime Protection | No (pure scanner) | No (pure scanner) | No (pure scanner) | Yes (part of broader CNAPP) |
| Pricing Model | Free | Free | Free tier for basic scanning, paid plans for higher usage, advanced features, and enterprise support (at the time of writing - check the vendor's pricing page) | Subscription-based, typically enterprise pricing (at the time of writing - check the vendor's pricing page) |
Trivy stands out for its simplicity, broad scanning capabilities beyond just containers, and excellent CI/CD integration. It's an ideal choice for teams looking for a reliable, open-source vulnerability scanner that's easy to deploy and manage. For more advanced features like runtime protection, compliance reporting, or deeper policy enforcement across a large enterprise, commercial solutions like Aqua Security CSP or Docker Scout's paid tiers might be considered.
Frequently Asked Questions
What is the difference between image scanning and runtime scanning?
Image scanning (what Trivy primarily does) analyzes container images for vulnerabilities before they are deployed. It's a "shift-left" security approach. Runtime scanning monitors running containers for suspicious activity, policy violations, or newly discovered vulnerabilities that might affect already deployed images. Both are crucial for comprehensive security.
Can Trivy scan my application code for vulnerabilities?
Trivy can scan application dependencies within a container image (e.g., Node.js packages, Python libraries). It can also scan local filesystems and Git repositories for IaC misconfigurations and vulnerabilities in language-specific dependency files. However, it is not a static application security testing (SAST) tool designed to find logical flaws or security bugs directly in your custom application code.
How often should I run container security scans?
You should run container security scans with every image build and ideally on every pull request to catch vulnerabilities as early as possible. Additionally, consider scheduled scans for images already in your registry or production to detect newly disclosed vulnerabilities that may affect previously "clean" images.
What should I do if Trivy finds a critical vulnerability?
If Trivy finds a critical vulnerability and your CI/CD pipeline fails, you should prioritize remediation. This typically involves updating the vulnerable package to a fixed version, rebuilding the image, and re-running the scan. If no fix is available, you might need to find an alternative package, isolate the component, or apply mitigating controls while awaiting a patch.
Can Trivy integrate with security dashboards or SIEM systems?
Yes, Trivy's JSON and SARIF output formats are machine-readable and can be parsed by other tools. You can write custom scripts to ingest Trivy's JSON reports into security dashboards, SIEM (Security Information and Event Management) systems, or issue trackers (like Jira) for centralized vulnerability management and alerting.
Is Trivy suitable for large-scale enterprise environments?
Trivy is highly scalable and suitable for enterprise environments. Its single-binary nature and efficient scanning make it easy to integrate across many pipelines. For centralized management, reporting, and advanced features like policy enforcement at scale, enterprises often combine Trivy with commercial solutions or build custom orchestration layers around it.
Automating container security scanning with Trivy in your CI/CD pipeline is a fundamental step towards building secure, resilient applications. By integrating these checks early and consistently, you significantly reduce your attack surface and enhance your overall security posture. Start by implementing a basic scan, then gradually refine your policies and integrate reporting to build a reliable, "shift-left" security strategy.
Your next steps should involve:
- Choose your CI/CD platform (GitHub Actions or GitLab CI) and adapt one of the provided examples to your project.
- Start with a lenient
--severitythreshold (e.g.,CRITICAL) and gradually increase it as your team becomes comfortable with addressing findings. - Explore Trivy's various output formats and consider integrating SARIF reports into GitHub's Security tab or parsing JSON output for custom dashboards.
- Regularly review Trivy's documentation for new features, scanning capabilities, and best practices to keep your security automation up-to-date.
Official documentation
- Trivy Documentation
- GitHub Actions Documentation
- GitLab CI/CD Documentation
- Docker Documentation
- GitHub Security Tab
- Trivy Air-Gapped Environment
- GitLab CI/CD Job Artifacts
- Trivy Vulnerability Exceptions



