DevOpsSecurity·

Automate Container Security with Trivy in GitHub Actions

Learn how to integrate Trivy into your CI/CD pipeline for automated vulnerability scanning in GitHub Actions.

Security is a critical component of modern DevOps practices. As development cycles accelerate, manually checking for vulnerabilities in dependencies, containers, and infrastructure becomes impractical. This is where Trivy shines. Trivy is an open-source, simple, and comprehensive vulnerability scanner developed by Aqua Security. It supports:

  • Container image scanning (Docker, OCI)
  • Filesystem scanning (OS packages, language-specific dependencies)
  • Infrastructure as Code (IaC) scanning (Terraform, Kubernetes, CloudFormation)
  • SBOM (Software Bill of Materials) generation

By integrating Trivy into your GitHub Actions workflow, you automate security checks ensuring vulnerabilities are caught early and reducing the risk of deploying insecure code.

The Workflow File

Below are example YAML files to get you started. This workflow builds and scans your Docker image for vulnerabilities on every push.

I propose 2 different workflows. The first one, With GitHub Security Report, generates a GitHub compatible Security Report in SARIF that is uploaded to your repo's Security tab via a dedicated action: github/codeql-action/upload-sarif. After the upload, I re-run Trivy with an exit-code: 1 to get an error if a critical or high vulnerability is found.

The second workflow, Without GitHub Security Report, is a simplified version where the SARIF report is not generated and uploaded. Only the Trivy console output is shown on the runner logs, and the job fails for critical or high vulnerabilities found.

GitHub Security Report
If you are on a GitHub Free or GitHub Pro plan, you can only use GitHub Security Report on repositories that are publicly available. To enable this feature for private or internal repositories, you must upgrade to GitHub Team or GitHub Enterprise with GitHub Code Security and enable Code Security in the repository settings.
name: Trivy example workflow

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build Docker image
        uses: docker/build-push-action@v5
        with:
          outputs: type=docker,dest=${{ runner.temp }}/my-image.tar

      - name: Upload image artifact
        uses: actions/upload-artifact@v4
        with:
          name: my-image
          path: ${{ runner.temp }}/my-image.tar
          retention-days: 1

  trivy-scan:
    runs-on: ubuntu-latest
    needs: build
    permissions:
      contents: read
      actions: read
      security-events: write # Needed for Security report upload

    steps:
      - name: Download image artifact
        uses: actions/download-artifact@v5
        with:
          name: my-image
          path: ${{ runner.temp }}

      - name: Generate Trivy vulnerability report
        uses: aquasecurity/trivy-action@master
        with:
          input: ${{ runner.temp }}/my-image.tar
          format: sarif
          output: trivy-results.sarif
          severity: HIGH,CRITICAL
          exit-code: 0 # The job won't fail on vulnerability findings

      - name: Upload Trivy report to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: trivy-results.sarif
          category: trivy-scan

      - name: Fail Trivy on High/Critical vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          input: ${{ runner.temp }}/my-image.tar
          format: table
          output: trivy-results.sarif
          severity: HIGH,CRITICAL
          exit-code: 1
          skip-setup-trivy: true # Trivy has already been intalled so we can skip it
You can change severity input to scan and display different severities of vulnerabilities. Available severities are: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL.

Next Steps: Adding Deployment

These workflows provide a solid foundation for container security scanning. A natural next step is to add a deployment job that runs only after successful security scans. I will propose a guide to explain how to push your Docker images to AWS ECR very soon.