Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Docker & Containerization

Container Vulnerability Scanning with Trivy in Your CI/CD Pipeline

We add Trivy to your CI/CD pipeline so every image is scanned for known OS and library vulnerabilities before it reaches the registry. Builds fail on agreed severities, findings are reported where developers work, and a documented exception process keeps the gate from becoming noise.

Key takeaways

  • Scan on every build and again on a schedule, because new CVEs appear against old images.
  • Gate on severity and fix availability, not on every finding, or developers will route around the scanner.
  • Findings are shown in pull requests or the security tab, not buried in logs.
  • Exceptions are written down with a reason and an expiry date.
  • Scanning is one layer: it finds known issues, not unknown ones or bad configuration on its own.

Why scanning in the pipeline matters

A vulnerability scanner that runs once a quarter produces a spreadsheet nobody acts on. A scanner that runs on every build, fails when it should and stays quiet when it should not becomes part of how engineers work. That difference is entirely about integration and policy, not about the tool.

Trivy is a good fit: it is open source, fast, needs no server, and handles OS packages, language dependencies and more. We wire it into your pipeline as part of our broader Docker containerisation service and alongside your CI/CD pipeline.

What good looks like

  • Every image is scanned after build and before it is pushed or promoted.
  • The build fails on findings that are serious and fixable.
  • Developers see results in the pull request, with the package, version and fixed version.
  • Deployed images are rescanned on a schedule.
  • Exceptions are visible, owned and time-limited.
  • An SBOM is generated and kept with the release.

A minimal pipeline step

This GitHub Actions job builds an image, scans it, and fails on fixable high and critical issues. Equivalent steps work in GitLab CI.

name: build
on: [pull_request]

jobs:
  image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/build-push-action@v6
        with:
          context: .
          load: true
          tags: myapp:${{ github.sha }}

      - name: Scan image
        uses: aquasecurity/[email protected]
        with:
          image-ref: myapp:${{ github.sha }}
          format: sarif
          output: trivy.sarif
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          exit-code: "1"

      - name: Upload results
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy.sarif

Version numbers for actions change, so we pin whatever is current when we implement and let Renovate propose updates. The same scan from a shell is a single line:

trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 myapp:1.4.2

Designing the policy

Severity and fix availability

Failing on critical and high with a fix available is a good starting point. Those are the findings a developer can act on today, by updating a package or rebuilding on a patched base. Findings without a fix are tracked, not blocking.

Where findings come from

In our experience, the largest share of findings in a typical image comes from the base operating system layer, not your application. That is why base image standardisation and image size reduction often cut scanner output more than any amount of triage.

Exceptions

Each exception needs a CVE identifier, a reason, an owner and a date to review. Keep them in version control. For findings where the vulnerable code is present but not reachable, a VEX statement documents that decision in a standard format.

Beyond vulnerabilities

Trivy can also scan more than packages:

  • trivy config . checks Dockerfiles, Terraform and Kubernetes manifests for risky settings.
  • trivy fs --scanners secret . looks for committed secrets.
  • trivy image --format cyclonedx produces an SBOM you can store with each release.

We enable these where they add signal. Not every check belongs in the blocking path on day one.

Scheduled rescans in practice

New advisories land daily, so a scan at build time is a snapshot. The scheduled job lists the images currently deployed, scans each against the latest database and reports only what changed since the last run. A sketch of the workflow trigger:

on:
  schedule:
    - cron: "0 5 * * *"
  workflow_dispatch: {}

The job output should go somewhere a person will see it: a ticket for the owning team, or a message to a security channel, carrying the service, the package and the fixed version. A rescan that nobody reads is no better than no rescan. When a critical issue appears, the answer to “which services are affected?” should be a list, and the answer to “what do we do?” should be to rebuild on a patched base, as described in base image standardisation.

Reading a finding

Developers who have never read scanner output need a short guide. Each finding has a package, an installed version, a fixed version (if any), a severity and a CVE identifier. The useful questions are: is the package actually used by my application or only present in the base image, is a fixed version available, and does the vulnerable code path apply to how we use it? Most of the time the fix is to update the base image or bump a dependency, not to analyse the CVE in depth. We include this guide in the handover so triage does not depend on a security specialist.

Keeping the scanner itself trustworthy

A security tool is part of your supply chain. We pin the scanner action or binary version, verify downloads where the project provides checksums or signatures, and update through reviewed pull requests like any other dependency. We also check that a deliberately vulnerable test image fails the gate, so you learn immediately if a configuration change has silently disabled it.

Decisions and trade-offs

Trivy, Grype, or the registry scanner? All three are credible. Trivy covers the widest scope in one binary. Grype pairs well with Syft for SBOM-centred workflows. Registry scanners give continuous monitoring without CI changes. We use what fits your tooling and avoid running several scanners that disagree and generate duplicate work.

Scan before or after pushing? Scan before the push to keep bad images out of the registry. Rescan after to catch new disclosures.

Database downloads in CI. Trivy fetches a vulnerability database each run. Cache it between runs, or mirror it internally, to avoid rate limits and slow jobs.

When not to gate hard. On a legacy estate with hundreds of existing findings, an immediate blocking gate stops all delivery. We start in report-only mode, fix the biggest sources, then turn on enforcement for new findings.

Common failure modes

  • Alert fatigue from thousands of unfixable findings. We filter by fixability and prioritise.
  • Bypassed scans because the pipeline allows overriding failures without a record. We require an exception entry instead.
  • Stale databases giving false confidence. We check that the database update step succeeds.
  • Scanning only the app image and ignoring sidecars, init containers and third-party images you run.

Delivery and handover

We provide pipeline templates for GitHub Actions and GitLab CI, a policy document with severities and exception rules, a scheduled rescan job, and a short runbook for triage. Findings feed the same process as the rest of your container hardening work.

How to tell it is working

Builds fail rarely and for good reasons, mean time to fix a critical finding drops, the exception list is short and current, and a newly published critical CVE produces a list of affected services within a day. To set this up in your pipelines, contact us.

References

How we deliver it

  1. 01

    Baseline your images

    We scan what is in the registry today to see the real starting position and the biggest sources of findings.

  2. 02

    Agree the policy

    Together we set which severities fail a build, whether unfixed findings count, and who approves exceptions.

  3. 03

    Add the scan to CI

    A pipeline step scans the built image before push, with cached vulnerability databases for speed.

  4. 04

    Publish results

    Output goes to SARIF, pull request comments or your security dashboard so developers see it where they work.

  5. 05

    Schedule rescans

    A nightly or weekly job rescans deployed images and alerts on newly disclosed critical issues.

  6. 06

    Triage and reduce

    We fix the largest causes first, usually base images, and record the remaining exceptions with expiry dates.

Tools and technologies

TrivyGitHub ActionsGitLab CISARIFGitHub code scanningAmazon ECR scanningGrypeSyftSBOMCycloneDXSPDXRenovate

Frequently asked questions

What does Trivy scan?
Trivy scans container images, filesystems and repositories for known vulnerabilities in OS packages and application dependencies, and can also check infrastructure-as-code files and Kubernetes manifests for misconfiguration, detect secrets, and produce software bills of materials. In this service we focus on images in the build pipeline.
Should a vulnerability fail the build?
Only when it is serious and actionable. We typically fail on high and critical findings that have a fix available, and report the rest. Failing on every finding, including those with no available patch, trains developers to ignore or bypass the scanner.
Why scan again after the image is built and deployed?
Because vulnerability databases keep growing. An image that was clean on Monday can have a critical finding on Friday without any change to the image. A scheduled rescan of deployed images catches this and tells you which services need a rebuild.
Is Trivy better than the scanner built into ECR or ACR?
They complement each other. Trivy runs in CI so a bad image never reaches the registry, and it is easy to tune. Registry scanning provides continuous monitoring of stored images. Many teams use both, with Trivy as the pipeline gate.
How do we deal with findings that cannot be fixed?
Record an exception with the CVE, the reason (not reachable, no fix available, mitigated elsewhere), an owner and an expiry date, usually in a .trivyignore file or a VEX statement. Exceptions that expire force a periodic re-check rather than permanent silence.

Talk to an engineer about trivy image scanning ci/cd

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.