Of all the security tools I’ve integrated into Jenkins pipelines, Trivy is by far the easiest to get started with, and it’s the one I recommend first to any team just beginning their container security journey. It’s open source, fast, requires no server setup, and runs as a single binary or container — no licensing negotiations, no complex API authentication flows. I added Trivy to a pipeline in an afternoon the first time I tried it, and it’s been part of every container-based project I’ve worked on since.
This guide covers everything from installing Trivy, running it inside Jenkins, scanning both images and infrastructure-as-code, and gating deployments based on findings.
Why Trivy for Container Security
Trivy, built by Aqua Security, is a comprehensive open-source scanner that detects:
- OS package vulnerabilities (Alpine, Debian, Ubuntu, CentOS, etc.)
- Application dependency vulnerabilities (npm, pip, Maven, Go modules, and more)
- Misconfigurations in Dockerfiles, Kubernetes manifests, and Terraform files
- Exposed secrets accidentally baked into image layers
- License compliance issues in dependencies
Because it runs as a lightweight CLI tool, it fits naturally into a Jenkins pipeline step without needing a separate scanning server or complex API polling like some enterprise DAST tools require.
Jenkins Architecture Context
Trivy scans typically run right after the docker build step and before docker push, catching vulnerable base images or dependencies before they ever reach a registry. Because Trivy is just a CLI, Jenkins invokes it directly via sh steps — there’s no REST API polling loop needed, which makes this one of the simplest security integrations to build and maintain.
Prerequisites
- Docker installed on the Jenkins agent (or a Docker-in-Docker/Kubernetes agent setup).
- Trivy installed on the agent, or available as a container image (
aquasec/trivy). - No license or API key required for the open-source version.
Step 1: Install Trivy on the Jenkins Agent
On a Debian/Ubuntu-based Jenkins agent:
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
Alternatively, skip installation entirely and just run Trivy as a Docker container, which is often cleaner for CI environments:
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image myapp:latest
Step 2: Basic Jenkinsfile with Trivy Image Scanning
pipeline {
agent any
environment {
IMAGE_NAME = 'myapp'
IMAGE_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Docker Image') {
steps {
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
}
}
stage('Trivy Vulnerability Scan') {
steps {
sh """
trivy image \
--severity HIGH,CRITICAL \
--exit-code 1 \
--format table \
--output trivy-report.txt \
${IMAGE_NAME}:${IMAGE_TAG}
"""
}
}
stage('Push Image') {
steps {
sh "docker push ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
post {
always {
archiveArtifacts artifacts: 'trivy-report.txt', allowEmptyArchive: true
}
failure {
mail to: 'devops-team@example.com',
subject: "Trivy Scan Failed: ${IMAGE_NAME}:${IMAGE_TAG}",
body: "High/Critical vulnerabilities detected. See attached report."
}
}
}
The --exit-code 1 flag is what makes Trivy actually fail the Jenkins build when it finds vulnerabilities at or above the specified severity — without it, Trivy just reports and exits 0 regardless of findings.
Step 3: JSON Output for Programmatic Gating
For more nuanced gating logic (say, allowing a small number of medium vulnerabilities but blocking on any critical), use JSON output and parse it with readJSON:
stage('Trivy Scan with Custom Gating') {
steps {
sh """
trivy image --format json --output trivy-results.json ${IMAGE_NAME}:${IMAGE_TAG}
"""
script {
def results = readJSON file: 'trivy-results.json'
def criticalCount = 0
results.Results.each { result ->
result.Vulnerabilities?.each { vuln ->
if (vuln.Severity == 'CRITICAL') {
criticalCount++
}
}
}
if (criticalCount > 0) {
error "Found ${criticalCount} CRITICAL vulnerabilities. Failing build."
} else {
echo "No critical vulnerabilities found."
}
}
}
}
Step 4: Using the Trivy Jenkins Plugin
There’s also an official Trivy plugin for Jenkins that provides built-in report visualization:
stage('Trivy Scan') {
steps {
trivy(
image: "${IMAGE_NAME}:${IMAGE_TAG}",
severity: 'HIGH,CRITICAL',
format: 'table'
)
}
}
(Note: plugin availability and exact syntax may vary by version — check the plugin page for the latest usage details.)
Scanning Dockerfiles and IaC for Misconfigurations
Trivy isn’t limited to scanning built images — it can also scan your Dockerfile and Kubernetes/Terraform manifests directly for misconfigurations before you even build:
stage('Trivy Config Scan') {
steps {
sh 'trivy config --severity HIGH,CRITICAL --exit-code 1 .'
}
}
This catches issues like running containers as root, missing resource limits in Kubernetes manifests, or overly permissive Terraform security group rules — all before the image is even built.
Scanning for Exposed Secrets
Trivy also includes a secret-scanning mode, useful for catching accidentally committed API keys or credentials baked into image layers:
stage('Trivy Secret Scan') {
steps {
sh "trivy image --scanners secret ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
Integrating with Git and GitHub
Report scan status directly on pull requests:
post {
failure {
githubNotify status: 'FAILURE', context: 'trivy-scan', description: 'Critical vulnerabilities found'
}
success {
githubNotify status: 'SUCCESS', context: 'trivy-scan', description: 'No critical vulnerabilities'
}
}
Integrating with Kubernetes
For clusters already running workloads, Trivy Operator can continuously scan images running in your cluster, complementing the CI-time scan with runtime visibility:
apiVersion: aquasecurity.github.io/v1alpha1
kind: VulnerabilityReport
Jenkins-triggered scans catch issues before deployment; the Trivy Operator catches new CVEs discovered after deployment for images that haven’t changed but whose vulnerability databases have been updated.
Integrating with Maven and Application Dependencies
Beyond container images, Trivy can scan a filesystem directly for language-specific dependency vulnerabilities, useful for Java/Maven projects even before containerization:
stage('Trivy Filesystem Scan') {
steps {
sh 'trivy fs --severity HIGH,CRITICAL --exit-code 1 .'
}
}
This catches vulnerable dependencies declared in pom.xml, package.json, requirements.txt, and similar manifest files.
Monitoring and Reporting
For teams wanting a persistent, searchable history of scan results beyond individual build artifacts, consider piping Trivy JSON output into a centralized dashboard like DefectDojo or Elastic/Kibana. This gives you trend analysis across builds — “are we introducing more vulnerabilities over time, or fewer?” — which is hard to answer from individual Jenkins console logs alone.
Troubleshooting Common Issues
- Trivy database download failures — Trivy downloads a vulnerability database on first run; if your Jenkins agents have restricted network access, mirror the database internally or use
--skip-db-updatewith a pre-cached DB. - Slow scans on large images — cache the Trivy vulnerability database between builds using a persistent volume or Docker volume mount to avoid re-downloading it every run.
- Too many findings on legacy images — start with
--severity CRITICALonly, then progressively tighten toHIGH,CRITICALas your team works through the backlog.
Best Practices
- Scan images immediately after build, before pushing to any registry.
- Use
--exit-code 1combined with--severityto enforce real gating, not just reporting. - Cache the Trivy vulnerability database locally to speed up repeated scans.
- Combine image scanning with
trivy configfor Dockerfile/Kubernetes/Terraform misconfiguration checks. - Run
trivy fsscans early for language dependency vulnerabilities, even before a container image exists. - Pair CI-time scanning with a runtime tool (like Trivy Operator) for ongoing visibility into deployed workloads.
FAQs
Is Trivy really free for commercial use? Yes, Trivy is fully open source under the Apache 2.0 license, with no licensing fees for commercial or enterprise use.
Can Trivy scan private registries? Yes, Trivy supports scanning images directly from private registries (ECR, GCR, Docker Hub private repos, Harbor) given proper registry authentication.
How often is the Trivy vulnerability database updated? Trivy’s vulnerability database updates multiple times daily, pulling from sources like NVD, GitHub Security Advisories, and various OS vendor security trackers.
Does Trivy replace the need for a DAST tool like Burp Suite or Acunetix? No — Trivy focuses on known vulnerabilities in packages/dependencies and misconfigurations (a form of SCA/IaC scanning), while DAST tools test running applications for exploitable behavior. They’re complementary, not interchangeable.
Summary
Trivy is one of the fastest ways to add meaningful, zero-cost container security scanning into a Jenkins pipeline. From scanning built images for known CVEs, to catching Dockerfile misconfigurations and exposed secrets, it slots cleanly into the build-before-push stage of any containerized CI/CD workflow. Combined with severity-based gating and artifact archiving, it gives your team continuous, low-friction visibility into the security posture of every image you ship.
References
- Trivy Official Documentation: https://aquasecurity.github.io/trivy/latest/
- Trivy GitHub Repository: https://github.com/aquasecurity/trivy
- Trivy Jenkins Plugin: https://plugins.jenkins.io/trivy/
- Trivy Operator for Kubernetes: https://aquasecurity.github.io/trivy-operator/latest/
