Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 14 min read

Trivy in Java Development: Complete Guide to Container Security Scanning

Trivy in Java Development: Complete Guide to Container Security Scanning Introduction Security vulnerability scanning has become non-negotiable in modern Java development. Container image vulnerabilities, de

Trivy in Java Development: Complete Guide to Container Security Scanning

Introduction

Security vulnerability scanning has become non-negotiable in modern Java development. Container image vulnerabilities, dependency exploits, and misconfigurations can compromise entire systems before they reach production. Trivy is an open-source vulnerability scanner that has emerged as the industry standard for container security assessment.

This comprehensive guide explores how to integrate Trivy into your Java development workflow, from local development to CI/CD pipelines, with practical code examples and real-world best practices.

What is Trivy?

Trivy is a lightweight, comprehensive vulnerability scanner developed by Aqua Security. It scans container images, filesystems, and Git repositories for:

  • OS Package Vulnerabilities (Alpine, Debian, Ubuntu, CentOS, etc.)
  • Application Dependencies (Maven, Gradle, pip, npm, Cargo, Bundler, Composer, etc.)
  • Infrastructure-as-Code Misconfigurations (Kubernetes manifests, Terraform, CloudFormation, Docker Compose)
  • Secrets exposed in code or configuration files (API keys, credentials, tokens)
  • Compliance Issues (license violations, policy breaches)

Trivy's speed and accuracy make it perfect for integration into CI/CD pipelines without causing bottlenecks. It's written in Go, making it highly efficient and portable across platforms.

Why Trivy vs Other Scanners?

Trivy stands out because of:

  • Speed: Scans container images in seconds
  • Simplicity: Zero configuration required to get started
  • Accuracy: Minimal false positives with regular database updates
  • Compatibility: Works with all major container registries (Docker Hub, ECR, GCR, Artifactory)
  • Open Source: Community-driven with frequent updates

Why Trivy Matters for Java Developers

Java applications typically depend on numerous third-party libraries. Maven Central and other repositories contain millions of packages, many with known vulnerabilities. A single vulnerable dependency can:

  • Enable remote code execution (RCE) attacks
  • Allow data breach attacks through exposed credentials
  • Violate compliance requirements (GDPR, PCI-DSS, HIPAA, SOC2)
  • Delay production deployments and impact revenue
  • Expose organizations to legal liability

Real-world examples include Log4Shell (CVE-2021-44228), which affected millions of Java applications overnight. Organizations without vulnerability scanning discovered the breach through external security researchers.

Trivy scanning catches these issues early, enabling rapid remediation before deployment to production.

Installation and Setup

Local Installation Methods

# Using Homebrew (macOS/Linux)
brew install trivy

# Using apt (Debian/Ubuntu)
sudo apt-get install trivy

# Using snap (Ubuntu/Linux)
sudo snap install trivy

# Using Docker (Universal - no installation needed)
docker run aquasec/trivy --version

# From GitHub releases (Linux x86_64)
wget https://github.com/aquasecurity/trivy/releases/download/v0.48.0/trivy_0.48.0_Linux-64bit.tar.gz
tar zxvf trivy_0.48.0_Linux-64bit.tar.gz
sudo mv trivy /usr/local/bin/

# Windows using Chocolatey
choco install trivy

# For Windows manual installation
# Download from https://github.com/aquasecurity/trivy/releases
# Extract and add to PATH

Verify Installation

trivy --version
trivy --help
trivy image --help
trivy fs --help
trivy config --help

Basic Trivy Commands for Java Developers

1. Scan a Docker Image

# Scan a local Docker image with default settings
trivy image mycompany/my-java-app:latest

# Scan with detailed output showing all severity levels
trivy image --severity LOW,MEDIUM,HIGH,CRITICAL mycompany/my-java-app:latest

# Scan showing only CRITICAL and HIGH vulnerabilities
trivy image --severity HIGH,CRITICAL mycompany/my-java-app:latest

# Generate JSON report for programmatic processing
trivy image --format json --output report.json mycompany/my-java-app:latest

# Generate table format report
trivy image --format table --output report.txt mycompany/my-java-app:latest

# Quiet mode - only show vulnerabilities
trivy image --quiet mycompany/my-java-app:latest

# Detailed output with description
trivy image --severity CRITICAL --format sarif --output trivy.sarif mycompany/my-java-app:latest

2. Scan Maven Project Dependencies

# Scan entire filesystem including pom.xml
trivy fs .

# Scan with severity filter
trivy fs --severity CRITICAL .

# Scan specific directory
trivy fs ./src --severity HIGH,CRITICAL

# Generate SBOM (Software Bill of Materials)
trivy fs --format cyclonedx --output sbom.xml .

# Generate SPDX format
trivy fs --format spdx --output sbom.spdx .

# Skip database update for faster scans (use existing cache)
trivy fs --skip-db-update .

# List all detected dependencies without vulnerabilities
trivy fs --severity NONE .

3. Scan Gradle Projects

Trivy automatically detects build.gradle and build.gradle.kts files:

# Scan Gradle project
trivy fs --skip-db-update my-gradle-project/

# Include lock files for precise version detection
trivy fs my-gradle-project/gradle.lockfile

# Scan with custom config
trivy fs --config trivy-config.yaml my-gradle-project/

# Output in different formats
trivy fs --format json my-gradle-project/ > gradle-scan.json

4. Scan Container Registry Images

# Scan image from Docker Hub
trivy image library/tomcat:9.0

# Scan from private registry with basic auth
trivy image --registry-token mytoken private-registry.io/my-image:latest

# Scan from AWS ECR
trivy image 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest

# Scan from Google Container Registry (GCR)
trivy image gcr.io/my-project/my-app:latest

# Scan from Azure Container Registry
trivy image myregistry.azurecr.io/my-app:latest

Integration with Maven-Based Java Projects

Maven POM Configuration

For Maven projects, create profiles that run Trivy scanning as part of the build:

<!-- pom.xml -->
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>secure-java-app</artifactId>
  <version>1.0.0</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <profiles>
    <profile>
      <id>security-scan</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
              <execution>
                <id>trivy-scan-dependencies</id>
                <phase>verify</phase>
                <goals>
                  <goal>run</goal>
                </goals>
                <configuration>
                  <target>
                    <echo message="Starting Trivy vulnerability scan..."/>
                    <exec executable="trivy" failonerror="true">
                      <arg value="fs"/>
                      <arg value="--severity"/>
                      <arg value="HIGH,CRITICAL"/>
                      <arg value="--exit-code"/>
                      <arg value="1"/>
                      <arg value="."/>
                    </exec>
                  </target>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>

    <profile>
      <id>docker-scan</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
              <execution>
                <id>docker-build-and-scan</id>
                <phase>package</phase>
                <goals>
                  <goal>run</goal>
                </goals>
                <configuration>
                  <target>
                    <echo message="Building Docker image..."/>
                    <exec executable="docker">
                      <arg value="build"/>
                      <arg value="-t"/>
                      <arg value>myapp:${project.version}</arg>
                      <arg value="-t"/>
                      <arg value>myapp:latest</arg>
                      <arg value="."/>
                    </exec>

                    <echo message="Scanning Docker image with Trivy..."/>
                    <exec executable="trivy" failonerror="true">
                      <arg value="image"/>
                      <arg value>--severity</arg>
                      <arg value>CRITICAL</arg>
                      <arg value>--exit-code</arg>
                      <arg value>1</arg>
                      <arg value>myapp:${project.version}</arg>
                    </exec>
                  </target>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

  <dependencies>
    <!-- Example dependencies -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>3.1.5</version>
    </dependency>
  </dependencies>
</project>

Run the scans:

# Scan dependencies
mvn clean verify -P security-scan

# Build and scan Docker image
mvn clean package -P docker-scan

# Run both profiles
mvn clean package -P security-scan,docker-scan

Gradle Integration

Gradle Build Script Configuration

// build.gradle
plugins {
    id 'java'
    id 'com.google.cloud.tools.jib' version '3.3.1'
}

sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:3.1.5'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.1.5'
}

// Custom task for Trivy filesystem scanning
tasks.register('trivyScan') {
    group = 'verification'
    description = 'Run Trivy vulnerability scanner on project dependencies'
    doLast {
        println "Starting Trivy vulnerability scan..."
        def result = exec {
            commandLine 'trivy', 'fs', 
                '--severity', 'HIGH,CRITICAL',
                '--exit-code', '1',
                '.'
            ignoreExitValue = true
        }

        if (result.exitValue != 0) {
            throw new GradleException("Trivy found vulnerabilities")
        }
    }
}

// Custom task for Docker image scanning
tasks.register('trivyImageScan') {
    group = 'verification'
    description = 'Scan Docker image for vulnerabilities'
    dependsOn 'build'
    doLast {
        def imageName = "myapp:${version}"
        println "Scanning Docker image: ${imageName}"

        exec {
            commandLine 'docker', 'build', '-t', imageName, '.'
        }

        exec {
            commandLine 'trivy', 'image',
                '--severity', 'HIGH,CRITICAL',
                '--exit-code', '1',
                imageName
        }
    }
}

// Add to verify task
tasks.named('verify').configure {
    dependsOn trivyScan
}

// For CI/CD pipelines
task cicd {
    dependsOn('clean', 'build', 'trivyScan', 'trivyImageScan')
}

For Kotlin DSL:

// build.gradle.kts
plugins {
    java
    id("com.google.cloud.tools.jib") version "3.3.1"
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web:3.1.5")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa:3.1.5")
    testImplementation("junit:junit:4.13.2")
}

tasks.register("trivyScan") {
    group = "verification"
    description = "Run Trivy vulnerability scanner"
    doLast {
        exec {
            commandLine("trivy", "fs", 
                "--severity", "HIGH,CRITICAL",
                "--exit-code", "1",
                ".")
        }
    }
}

tasks.named("verify") {
    dependsOn("trivyScan")
}

CI/CD Pipeline Integration

GitHub Actions Workflow

# .github/workflows/security-scan.yml
name: Container Security Scan

on:
  push:
    branches: [main, develop, release/**]
  pull_request:
    branches: [main]
  schedule:
    # Daily scan at 2 AM UTC
    - cron: '0 2 * * *'

permissions:
  contents: read
  security-events: write
  pull-requests: write

jobs:
  trivy-scan:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        java-version: ['11', '17', '21']

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java-version }}
          distribution: 'temurin'
          cache: maven

      - name: Build with Maven
        run: mvn clean package -DskipTests

      - name: Build Docker image
        run: |
          docker build -t myapp:${{ github.sha }} .
          docker tag myapp:${{ github.sha }} myapp:latest

      - name: Run Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Run Trivy filesystem scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-fs-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Upload SARIF to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: 'trivy-*.sarif'

      - name: Generate JSON reports
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: 'json'
          output: 'trivy-image-report.json'

      - name: Parse and comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const report = JSON.parse(fs.readFileSync('trivy-image-report.json', 'utf8'));

            let critical = 0;
            let high = 0;

            report.Results?.forEach(result => {
              result.Vulnerabilities?.forEach(vuln => {
                if (vuln.Severity === 'CRITICAL') critical++;
                else if (vuln.Severity === 'HIGH') high++;
              });
            });

            const comment = `## πŸ”’ Security Scan Results

            - Critical Issues: ${critical}
            - High Issues: ${high}

            [View detailed scan](${{ github.server_url }}/${{ github.repository }}/security/code-scanning)`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });

GitLab CI Integration

# .gitlab-ci.yml
stages:
  - build
  - scan
  - deploy

variables:
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: "/certs"

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:latest

trivy_scan:
  stage: scan
  image: aquasec/trivy:latest
  variables:
    TRIVY_NO_PROGRESS: "true"
    TRIVY_CACHE_DIR: ".trivycache"
    TRIVY_FORMAT: "sarif"
    TRIVY_OUTPUT: "trivy-report.sarif"
  cache:
    paths:
      - .trivycache
  script:
    - trivy image --severity HIGH,CRITICAL --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - trivy image --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  artifacts:
    reports:
      sast: trivy-report.sarif
    paths:
      - trivy-report.sarif
    expire_in: 30 days
  allow_failure: false

trivy_fs_scan:
  stage: scan
  image: aquasec/trivy:latest
  script:
    - trivy fs --severity HIGH,CRITICAL --exit-code 1 .
  allow_failure: false

Jenkins Pipeline

// Jenkinsfile
@Library('shared-library') _

pipeline {
    agent any

    environment {
        APP_NAME = "secure-java-app"
        REGISTRY = "docker.io"
        IMAGE_TAG = "${BUILD_ID}"
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                script {
                    sh '''
                        echo "Building Maven project..."
                        mvn clean package -DskipTests
                    '''
                }
            }
        }

        stage('Build Docker Image') {
            steps {
                script {
                    sh '''
                        echo "Building Docker image: ${APP_NAME}:${IMAGE_TAG}"
                        docker build -t ${REGISTRY}/${APP_NAME}:${IMAGE_TAG} .
                        docker tag ${REGISTRY}/${APP_NAME}:${IMAGE_TAG} ${REGISTRY}/${APP_NAME}:latest
                    '''
                }
            }
        }

        stage('Trivy Scan') {
            steps {
                script {
                    sh '''
                        echo "Running Trivy container image scan..."
                        trivy image \
                            --severity CRITICAL,HIGH \
                            --format json \
                            --output trivy-image-report-${BUILD_ID}.json \
                            ${REGISTRY}/${APP_NAME}:${IMAGE_TAG} || true

                        echo "Running Trivy filesystem scan..."
                        trivy fs \
                            --severity CRITICAL,HIGH \
                            --format json \
                            --output trivy-fs-report-${BUILD_ID}.json \
                            . || true
                    '''
                }
            }
        }

        stage('Parse Scan Results') {
            steps {
                script {
                    sh '''
                        echo "Analyzing Trivy results..."
                        python3 << 'PYTHON'
import json

# Parse image scan
with open('trivy-image-report-${BUILD_ID}.json') as f:
    report = json.load(f)
    critical = 0
    high = 0
    for result in report.get('Results', []):
                        for vuln in result.get('Vulnerabilities', []):
                            if vuln['Severity'] == 'CRITICAL':
                                critical += 1
                            elif vuln['Severity'] == 'HIGH':
                                high += 1

                        print(f"Image Scan - CRITICAL: {critical}, HIGH: {high}")
                        if critical > 0:
                            exit(1)
PYTHON
                    '''
                }
            }
        }

        stage('Push Image') {
            when {
                branch 'main'
            }
            steps {
                script {
                    sh '''
                        docker push ${REGISTRY}/${APP_NAME}:${IMAGE_TAG}
                        docker push ${REGISTRY}/${APP_NAME}:latest
                    '''
                }
            }
        }
    }

    post {
        always {
            script {
                sh '''
                    # Publish HTML reports
                    mkdir -p reports
                    cp trivy-*-report-*.json reports/ || true
                '''
            }

            publishHTML([
                reportDir: 'reports',
                reportFiles: 'trivy-*.json',
                reportName: 'Trivy Vulnerability Reports'
            ])
        }
    }
}

Performance Optimization

Database Management

# Pre-download vulnerability database
trivy image --download-db-only
trivy image --download-java-db-only

# Use cached database for faster scans
trivy image --skip-db-update myapp:latest

# Check database freshness
trivy image --list-all-pkgs myapp:latest

# Custom cache directory
trivy --cache-dir /data/trivy-cache image myapp:latest

Parallel Scanning

#!/bin/bash
# Scan multiple images in parallel
find . -name "Dockerfile" | \
  parallel "echo 'Scanning {}'; \
  docker build -t test-image-{#} -f {} . && \
  trivy image --quiet test-image-{#}"

Advanced Topics

Vulnerability Policy as Code

# trivy-policy.rego (Rego policy for advanced filtering)
package trivy

# Fail on critical vulnerabilities
deny[msg] {
    input.ArtifactType == "container_image"
    vuln := input.Results[_].Vulnerabilities[_]
    vuln.Severity == "CRITICAL"
    msg := sprintf("Found critical vulnerability: %s", [vuln.VulnerabilityID])
}

# Warn on high vulnerabilities
warn[msg] {
    vuln := input.Results[_].Vulnerabilities[_]
    vuln.Severity == "HIGH"
    msg := sprintf("Found high severity vulnerability: %s", [vuln.VulnerabilityID])
}

Software Bill of Materials (SBOM)

# Generate CycloneDX SBOM
trivy image --format cyclonedx --output sbom.xml myapp:latest

# Generate SPDX SBOM
trivy image --format spdx --output sbom.spdx myapp:latest

# Analyze SBOM with tools
cyclonedx-cli validate --input-file sbom.xml

Conclusion

Trivy has become essential infrastructure for Java development organizations. By integrating Trivy into build pipelines, developers catch vulnerabilities at every stageβ€”from local development through production deployment.

Key takeaways:

  • Integrate early: Scan during development, not just at deployment
  • Automate: Use CI/CD to enforce scanning policies consistently
  • Monitor continuously: Scan existing images regularly for newly discovered vulnerabilities
  • Remediate promptly: Establish clear policies for vulnerability response
  • Document: Maintain SBOMs and scan reports for compliance and audit

As supply chain attacks continue to rise, Trivy provides the visibility and control needed to keep Java applications secure in production.

Ready to secure your Java applications? Start with local Trivy scanning on your Maven or Gradle projects today, then integrate into your CI/CD pipeline for comprehensive security coverage.

Troubleshooting Common Issues

Issue 1: "Database Fetch Failed" Error

# Problem: Trivy cannot download the vulnerability database
trivy image myapp:latest
# Error: failed to download the vulnerability database

# Solution 1: Update database manually
trivy image --download-db-only
trivy image myapp:latest

# Solution 2: Use offline mode if database exists
trivy image --skip-db-update myapp:latest

# Solution 3: Set custom database repository
trivy --db-repository ghcr.io/aquasecurity/trivy-db image myapp:latest

Issue 2: False Positives and Whitelisting

# Create .trivyignore file in project root
cat > .trivyignore << 'IGNORE'
# Format: CVE-YYYY-XXXXX [exp:YYYY-MM-DD] [justification]

# Log4Shell - patched in our environment
CVE-2021-44228 exp:2025-01-01 "Patched in Log4j 2.18.0"

# False positive for our Spring Boot configuration
CVE-2023-12345 "Not applicable to our deployment model"

# Third-party library - vendor confirmed safe
CVE-2023-54321 "Vendor security statement confirms safe"
IGNORE

# Run scan with ignore file
trivy image --ignorefile .trivyignore myapp:latest

Issue 3: Slow Scans on Large Images

# Optimize scan performance

# Skip unnecessary components
trivy image --skip-files "*.md,*.txt" \
            --skip-dirs "docs,test,examples" \
            myapp:latest

# Use parallel scanning with xargs
ls Dockerfiles/* | xargs -P 4 -I {} trivy image {}

# Download database once, reuse in scans
trivy image --download-db-only
time trivy image --skip-db-update myapp:latest

Issue 4: Private Registry Authentication

# Docker Hub with credentials
trivy image \
    --registry-token $(echo -n "username:password" | base64) \
    docker.io/private-org/app:latest

# AWS ECR authentication
aws ecr get-login-password --region us-east-1 | \
  trivy image --registry-token $(cat) \
  123456789.dkr.ecr.us-east-1.amazonaws.com/app:latest

# Google Container Registry with service account
cat /path/to/service-account.json | \
  trivy image --registry-token $(cat) \
  gcr.io/project-id/app:latest

Real-World Use Cases

Use Case 1: Enterprise Security Gateway

// Enterprise security gate using Gradle
task securityGate {
    doLast {
        // 1. Scan dependencies
        exec {
            commandLine 'trivy', 'fs', '.', '--severity', 'CRITICAL'
            ignoreExitValue = true
        }

        // 2. Scan Docker image
        exec {
            commandLine 'docker', 'build', '-t', "enterprise-app:${version}", '.'
        }

        exec {
            commandLine 'trivy', 'image', "enterprise-app:${version}", 
                '--exit-code', '1'
        }

        // 3. Generate compliance report
        exec {
            commandLine 'trivy', 'image', "enterprise-app:${version}",
                '--format', 'json', '--output', 'compliance-report.json'
        }

        println "βœ… Enterprise security gate passed!"
    }
}

build.finalizedBy securityGate

Use Case 2: Scheduled Vulnerability Monitoring

#!/bin/bash
# trivy-monitor.sh - Daily vulnerability monitoring

LOG_DIR="/var/log/trivy-scans"
REPORT_EMAIL="[email protected]"
REGISTRY="docker.io/company"

mkdir -p "$LOG_DIR"

# Get all production images
IMAGES=$(curl -s https://registry.company.com/v2/_catalog | \
         jq -r '.repositories[] | select(contains("prod-")) | . + ":latest"')

CRITICAL_COUNT=0
REPORT_FILE="$LOG_DIR/scan-$(date +%Y%m%d-%H%M%S).txt"

for image in $IMAGES; do
    echo "Scanning: $image" | tee -a "$REPORT_FILE"

    trivy image "$image" --format json | \
    jq '.Results[].Vulnerabilities[] | 
        select(.Severity == "CRITICAL") | 
        {Image: "'$image'", CVE, Severity}' >> "$REPORT_FILE"

    CRITICAL=$(trivy image "$image" --format json | \
                jq '[.Results[].Vulnerabilities[] | 
                     select(.Severity == "CRITICAL")] | length')

    CRITICAL_COUNT=$((CRITICAL_COUNT + CRITICAL))
done

# Send email alert if critical vulnerabilities found
if [ $CRITICAL_COUNT -gt 0 ]; then
    mail -s "🚨 Trivy Alert: $CRITICAL_COUNT Critical Vulnerabilities" \
         "$REPORT_EMAIL" < "$REPORT_FILE"
fi

Use Case 3: Multi-Service Microservices Scanning

# docker-compose-scan.yml
version: '3.8'

services:
  api-service:
    image: company/api-service:latest
    labels:
      - "scan=true"

  auth-service:
    image: company/auth-service:latest
    labels:
      - "scan=true"

  database-service:
    image: postgres:15-alpine
    labels:
      - "scan=true"

# Scan script for compose services
# scan-compose.sh
#!/bin/bash
docker-compose config | grep -E "^\s+image:" | \
awk '{print $2}' | sed 's/"//g' | \
while read image; do
    echo "Scanning: $image"
    trivy image "$image" --severity HIGH,CRITICAL --exit-code 1
done

Integration with Security Tools

Slack Integration for Scan Results


bash
#!/bin/bash
# slack-trivy-notification.sh

SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
IMAGE="myapp:latest"

# Run scan
REPORT=$(trivy image --format json "$IMAGE")

# Extract vulnerability counts
CRITICAL=$(echo "$REPORT" | jq '[.Results[].Vulnerabilities[] | select(.Severity == "CRITICAL")] | length')
HIGH=$(echo "$REPORT" | jq '[.Results[].Vulnerabilities[] | select(.Severity == "HIGH")] | length')

# Create Slack message
PAYLOAD=$(cat <<EOF
{
  "text": "πŸ”’ Trivy Security Scan Complete",
  "attachments": [
    {
      "color": "$([ $CRITICAL -gt 0 ] && echo '#CC0000' || echo '#00CC00')",
      "fields": [
        {
          "title": "Image",
          "value": "$IMAGE",
          "short": true
        },
        {
          "title": "Critical",
          "value": "$CRITICAL",
          "short": true
        },
        {
          "title": "High",
          "value": "$HIGH",
          "short": true
        }
      ]
    }
  ]
}
πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.