Container Image Scanning in CI/CD: Catching Vulnerabilities Before Deployment
AI generated
OWASP
0x00
Security · Containers · CI/CD · Vulnerability Scanning
Container Image Scanning in CI/CD
finding vulnerabilities before they get deployed

A Docker image is made up of many layers of code someone else wrote: the base distribution, system-wide packages, a language runtime, and application dependencies. Any of those layers can carry known vulnerabilities without a developer ever having written a single line of that code themselves. Automated image scanning in the CI/CD pipeline surfaces those vulnerabilities before an image is even built toward production, preventing known gaps from quietly going live.

15 min read Trivy · Grype · CVE Databases CI Gate · SBOM · Base Images

1. Why image scanning has to be a fixed part of the pipeline

A production Docker image is rarely pure application code. It almost always contains a base distribution such as Debian or Alpine, plus system packages, a language runtime like PHP or Node.js, and a long list of libraries installed through a package manager. Every one of those components is maintained independently of your own team, which means new vulnerabilities can be publicly disclosed at any time even though nothing in your own application code has changed.

Without systematic scanning, the only way to catch such gaps is manually checking security advisories, which in practice rarely happens consistently. Automated scanning turns that check into a fixed, repeatable step of every pipeline run, making sure a new critical CVE does not go unnoticed for weeks, or forever.

2. How vulnerability scanners analyze an image

A scanner like Trivy or Grype takes a container image apart layer by layer and identifies the packages installed inside it using their metadata, such as Debian's package database or npm and Composer lockfiles. That package list then gets matched against one or more CVE databases that link known vulnerabilities to affected version ranges.

The result is a list of found vulnerabilities along with severity, affected package, installed version, and, where available, the version in which the gap was already fixed. That structured output can be evaluated programmatically, which is exactly what turns scanning into an automatable CI task rather than manual research.

3. Trivy versus Grype

Trivy from Aqua Security covers, beyond OS packages and application dependencies, misconfigurations, secrets embedded in the image, and license issues, making it a versatile tool for a single CI gate. Grype from Anchore focuses more narrowly on pure vulnerability detection but is considered especially precise in version evaluation, and pairs well with Anchore's SBOM tool Syft.

In practice the two tools differ less in fundamental capability than in details like scan speed, database freshness, and output format quality. Many teams deliberately run both in parallel, since different databases occasionally return different results, and a second source compensates for blind spots in a single database.


# GitHub Actions: Trivy scan as a mandatory gate before pushing to the registry
name: container-scan
on:
  push:
    branches: [main]

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t shop-app:${{ github.sha }} .

      - name: Run Trivy scan
        uses: aquasecurity/trivy-action@0.24.0
        with:
          image-ref: "shop-app:${{ github.sha }}"
          format: "table"
          exit-code: "1"
          severity: "CRITICAL,HIGH"
          ignore-unfixed: true

      - name: Push image to registry
        if: success()
        run: docker push registry.internal/shop-app:${{ github.sha }}

4. A CI gate that blocks the build on critical CVEs

An effective CI gate aborts the pipeline run with a non-zero exit code as soon as the scanner finds vulnerabilities above a defined severity threshold. In the example above, that happens through exit-code: 1 combined with severity: CRITICAL,HIGH, which means the following push step never runs and a vulnerable image never makes it into the registry at all.

It matters that the gate sits early in the workflow, right after the image is built and before any deployment step. A scan that runs but whose result is only shown as informational, without being enforced, quickly turns into an ignored warning that nobody takes seriously anymore once it becomes routine.

5. Choosing sensible severity thresholds

A gate that blocks on any vulnerability, no matter how low its severity, quickly leads to frustration in practice, since hardly any realistic base image is completely free of low-severity CVEs. A tiered approach works better, where critical and high vulnerabilities reliably stop the build while medium and low findings show up as warnings without automatically blocking anything.

The ignore-unfixed option is also worth using, since it hides vulnerabilities for which the package maintainer has not yet published a patch. Blocking a build over exactly that would be unproductive, because the team cannot do anything about it beyond waiting for an upstream fix or manually replacing the affected package.

6. Handling vulnerabilities in base images you do not control

A common problem is vulnerabilities buried deep in an official image's base distribution, in a library the operating system itself ships that nobody on your own team can directly influence. Here it helps to regularly move to leaner base images, such as distroless or Alpine-based variants, which inherently ship far fewer installed packages and therefore a smaller attack surface.

For cases where a fix simply does not exist yet but the risk is acceptable, there should be a documented exception process: a time-boxed ignore rule with a stated reason, an owner, and a follow-up date, rather than a silent, permanent suppression of the warning inside the scanner.

7. SBOM as a complement to a pure scan

A Software Bill of Materials, or SBOM, lists every component contained in an image along with its version, regardless of whether a vulnerability is currently known for it. Tools like Syft generate such a list in the standardized CycloneDX or SPDX format directly from a built image.

An SBOM's value shows most clearly when a new vulnerability in a widely used library goes public, as happened with log4shell. Instead of having to re-scan every single image from scratch, existing SBOMs let you instantly query which production images even contain the affected component, drastically cutting response time for such incidents.

8. Managing false positives and exceptions cleanly

Scanners occasionally flag vulnerabilities that are not actually exploitable in the concrete usage, for instance because the affected function of a library is never called in your own code. Ignoring such false positives blanket-style without documenting them eventually causes real findings to get lost in the noise.

Both Trivy and Grype support ignore files where individual CVE IDs can be excluded with a stated reason. Those files belong in version control and should be part of code review, so that every exception stays traceable and gets periodically checked for whether it is still justified.

9. Scanning in the registry versus in the CI pipeline run

Scanning directly in the CI pipeline catches vulnerabilities before an image even exists, proactively preventing vulnerable images from being created in the first place. Additional, periodic scanning of already-pushed images directly in the container registry instead covers vulnerabilities that only became publicly known after the original build, while the image itself sits unchanged in the registry.

Both layers complement each other well: the pipeline gate stops new gaps from being created, while registry scanning continuously re-evaluates images already in circulation, surfacing risks that became known later, long before an affected image gets deployed again.

Tool License Scan method Distinguishing trait
Trivy Apache 2.0 OS packages, dependencies, secrets, IaC all-in-one tool with very broad coverage
Grype Apache 2.0 OS packages and application dependencies precise version evaluation, pairs with Syft
Docker Scout commercial with free tier registry-integrated scanning built directly into the Docker ecosystem
Snyk Container commercial with free tier dependencies with fix recommendations strong prioritization and remediation guidance

Mironsoft

Security audits, OWASP-compliant hardening, and secure architecture

Applications that actually hold up against a real attack attempt?

We review existing applications for classic OWASP vulnerabilities, insecure authentication, and missing input validation, then build an architecture that structurally reduces attack surface instead of just patching individual symptoms.

Security Audit

Systematically checking OWASP Top 10, auth flows, and input validation for vulnerabilities.

Secure Architecture

Building rate limiting, encryption, and access controls correctly from the ground up.

Incident Readiness

Establishing logging, monitoring, and response processes for when things go wrong.

10. Summary

Container Image Scanning in CI/CD: The Essentials at a Glance

Core problem

Base images carry code you did not write, where new vulnerabilities can surface any time.

Tools

Trivy covers broadly, Grype is especially precise at pure vulnerability detection.

Enforcement

A CI gate checking the exit code reliably blocks the build on critical findings.

Handling residual risk

Time-boxed, documented exceptions instead of silent, permanent suppression.

11. FAQ: Container Image Scanning in CI/CD: The Essentials at a Glance

1What is container image scanning?
Container image scanning is the automated analysis of a Docker image for known vulnerabilities in OS packages and application dependencies, usually by matching against public CVE databases.
2What is the difference between Trivy and Grype?
Trivy also covers misconfigurations, secrets, and license issues beyond vulnerabilities, while Grype focuses more narrowly on precise vulnerability detection and pairs well with the SBOM tool Syft.
3How does a CI gate block the build on critical CVEs?
The scanner is configured to return a non-zero exit code as soon as vulnerabilities above a defined severity are found, which aborts the pipeline and prevents subsequent steps such as pushing to the registry from running.
4What do you do about vulnerabilities in base images you do not control?
Move to leaner base images such as distroless or Alpine variants to reduce the attack surface, and use a documented, time-boxed exception process for gaps that are not yet patched.
5What does ignore-unfixed do in Trivy?
This option hides vulnerabilities for which the package maintainer has not yet published a patch, since blocking a build over that would be unproductive, as the team cannot act on it immediately anyway.
6What is an SBOM and what is it used for?
A Software Bill of Materials lists every component contained in an image along with its version. It lets you instantly query, once a new vulnerability is disclosed, which production images even contain the affected component, without rescanning everything.
7How do you handle false positives in scanning?
Through documented ignore files where individual CVE IDs are excluded with a stated reason, rather than suppressing findings blanket-style without any traceability.
8Is a scan in the CI pipeline alone sufficient?
No, additional periodic scanning of already-pushed images in the registry is needed to catch vulnerabilities that only became publicly known after the original build.
9What severity should you use as the blocking threshold?
It is common to let critical and high vulnerabilities reliably stop the build while medium and low findings stay visible as warnings, so the pipeline is not paralyzed by practically unavoidable minor findings.
10How often should a registry scan be re-run?
Daily or several times a week, since new vulnerabilities can be publicly disclosed at any time, regardless of when an image was originally built.