Docker Image Scanning and Security Updates in CI
AI generated
Docker · Image Scanning · Security · CI/CD · CVE
Docker Image Scanning and Security Updates in CI
from Trivy and Grype to SBOM and automatic updates

A Docker image that gets built once and never checked for vulnerabilities again slowly turns into a security hole. Image scanning in the CI pipeline and automatic base image updates close that window before CVEs make it into production.

13 min read Trivy · Grype · Snyk · SBOM · Renovate · GitHub Actions Docker Engine 26+ · OCI · CVSS 3.x

1. Why image scanning in CI is essential

Docker image scanning is not an optional add-on to a security concept, it is a necessary part of any CI pipeline that builds container images for production use. The reason: even a base image that is secure today will contain known vulnerabilities tomorrow, as soon as CVEs get published for packages installed inside it. An image that gets built once and never checked again accumulates security gaps over time without anyone getting a warning.

The reality in many teams: images get built, deployed, and never rebuilt for months or years. Every new CVE publication affecting a package contained in the image stays invisible. Docker image scanning in the CI pipeline makes these gaps visible, at the latest during the next build, ideally also as a periodic scan of images already running in the registry. Teams that cover both layers, build time and registry, get a complete picture of the vulnerability status of their container stack.

2. Scanning tools at a glance: Trivy, Grype and Snyk

Trivy by Aqua Security is the best known open source tool for Docker image scanning. It can scan OS packages, application dependencies (Python, Ruby, Node, PHP Composer, Java Maven), configuration files and IaC files. Trivy uses the NVD and OS vendor vulnerability databases and updates them automatically on every run. Integration into GitHub Actions, GitLab CI and other CI systems is well documented and takes just a few lines of YAML.

Grype by Anchore is a strong alternative with a similar feature set. Its main advantage is the deeper integration with Syft, the companion SBOM tool: you generate an SBOM with Syft first and then let Grype check that SBOM for vulnerabilities. That cleanly separates scanning from inventory. Snyk is a commercial product with a free tier for small teams. Beyond plain Docker image scanning it also offers autofix suggestions and a web UI for managing vulnerabilities across multiple projects.


# .github/workflows/docker-security.yml: Image scanning in GitHub Actions
name: Docker Image Security Scan

on:
  push:
    branches: [main, develop]
  schedule:
    # Scan weekly even without new pushes: catch newly published CVEs
    - cron: '0 6 * * 1'

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

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

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          # Fail on HIGH and CRITICAL vulnerabilities
          severity: HIGH,CRITICAL
          # Ignore vulnerabilities without a fix (no point blocking on those)
          ignore-unfixed: true

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

3. Integrating Trivy into the CI pipeline

Trivy can be used as a CLI tool, as a Docker container, or as a GitHub Action. For CI pipelines the GitHub Action is the easiest way in; for more complex pipelines with a self-hosted runner, the Trivy container fits better. The most important decision when integrating it is where in the build process the scan happens: ideally right after the docker build step, before the image gets pushed to the registry. That way the build fails when critical vulnerabilities are found, and no insecure image ever reaches the registry.

Trivy's SARIF output format integrates seamlessly with GitHub Security, the GitLab Security Dashboard, and other platforms that understand SARIF. That means scan results show up directly in the pull request and developers can review them without any extra tooling layer. For local Docker image scanning without CI, trivy image imagename:tag does the job: within seconds you get a sorted table with every CVE found, its severity, CVSS score and available fix.

4. Defining CVSS thresholds and exceptions

A CI pipeline that stops the build on every CRITICAL CVE quickly becomes an obstacle once a critical CVE shows up in a transitive package that has no fix available yet. The solution: differentiated thresholds with an exception list for CVEs that are known, have no fix, and have been assessed as an acceptable risk for the specific use case. Trivy supports a .trivyignore file in the project directory where CVE IDs to be ignored during the scan can be listed.

A sensible escalation strategy for Docker image scanning in CI: CRITICAL CVEs with an available fix block the build. HIGH CVEs without a fix raise a warning but do not block. MEDIUM and LOW get documented but neither block nor warn. This strategy prevents builds from being permanently blocked by unfixable vulnerabilities, without letting real risks go unnoticed. The exception list needs regular review: as soon as a fix becomes available for an ignored CVE, the entry must be removed from the list.


# .trivyignore: Document each exception with reason and review date
# Format: CVE-ID [optional comment]

# CVE-2024-12345: libssl vulnerability, no fix available for alpine 3.19 base
# Review by: 2026-06-01
CVE-2024-12345

# CVE-2024-67890: zlib integer overflow, only exploitable via crafted ZIP files
# Our application does not process untrusted ZIP files (reviewed 2026-04-15)
CVE-2024-67890

---

# trivy.yaml: Project-level Trivy configuration
severity:
  - CRITICAL
  - HIGH

# Only fail on vulnerabilities that have a fix
ignore-unfixed: true

# Skip development dependencies (they don't end up in production images)
skip-dirs:
  - node_modules/.bin
  - vendor/bin

# Output formats for different purposes
format: table   # Human-readable for local use

# Scan timeout: useful for large images with many packages
timeout: 10m0s

5. Generating and using an SBOM

An SBOM (Software Bill of Materials) is a complete inventory of every package, library and dependency contained in an image, comparable to a packing slip for software. Docker image scanning and SBOM generation complement each other: the scan identifies current vulnerabilities, while the SBOM makes it possible to check an existing image against newly published CVEs at any later point without rebuilding it. That becomes especially valuable when a critical CVE gets published for a package and you need to figure out which running images are affected.

SPDX and CycloneDX are the relevant SBOM format standards. Trivy can generate SBOMs in both formats. Syft by Anchore is a dedicated SBOM tool that digs deeper into an image's package structure and can be used alongside Trivy. SBOMs are ideally stored together with the image in the registry, either as an OCI artifact or as a separate file. That enables later analysis without access to the build system and is already a stated requirement in some compliance frameworks.

6. Keeping base images current

Most CVEs in Docker images come from the base image, not from the application itself. The fastest way to bring the CVE count down is a current base image. php:8.4-fpm-alpine has far fewer installed packages, and therefore a far smaller attack surface, than the Debian-based php:8.4-fpm. Alpine images tend to be well maintained under active CVE programs and get updated faster than many other distribution images when critical vulnerabilities surface.

Base images should never be pinned to a fixed SHA digest in the Dockerfile without a process in place that regularly refreshes those digest pins. A pinned digest image looks like more control, but it is actually a static target: new security updates never come in automatically. The right pattern is a tag without SHA in the Dockerfile plus an automatic update process through Renovate or Dependabot that bumps the tag whenever a new image appears and opens a pull request.

7. Renovate for automatic Dockerfile updates

Renovate is an open source dependency update bot that checks Dockerfiles, compose files, GitHub Actions and many other configuration formats for outdated versions and automatically opens pull requests with updates. For Docker image scanning workflows, Renovate is the ideal companion: while the scan surfaces current vulnerabilities, Renovate keeps base images and dependencies current and feeds new patches automatically into a review process.

Renovate recognizes version patterns in Dockerfiles automatically: FROM php:8.4-fpm-alpine gets recognized as a versioned dependency, and Renovate checks whether a newer Alpine version is available. The configuration in renovate.json lets you enable automerge for patch updates (so minimal updates get applied automatically without manual review) while minor and major updates always require a manual review. That significantly cuts the manual effort for security updates without giving up control over significant version jumps.


# renovate.json: Automated Dockerfile and Docker Compose updates
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:best-practices"],
  "docker": {
    "enabled": true
  },
  "packageRules": [
    {
      "matchManagers": ["dockerfile", "docker-compose"],
      "matchUpdateTypes": ["patch"],
      "automerge": true,
      "automergeType": "pr",
      "addLabels": ["security", "auto-merge"]
    },
    {
      "matchManagers": ["dockerfile", "docker-compose"],
      "matchUpdateTypes": ["minor", "major"],
      "reviewers": ["team:platform"],
      "addLabels": ["security", "needs-review"]
    }
  ],
  "schedule": ["every weekend"],
  "prConcurrentLimit": 5
}

# Test Renovate configuration locally:
# npx renovate --token $GITHUB_TOKEN --dry-run=lookup owner/repo

8. Dockerfile hardening as the first line of defense

Beyond reactive Docker image scanning there are proactive measures inside the Dockerfile itself that shrink the attack surface from the start. The most important step: containers should never run as the root user. A dedicated non-root user in the Dockerfile prevents a compromised container process from directly reaching host resources if a container escape vulnerability gets exploited. The USER statement in the Dockerfile combined with correctly set file permissions takes just a few lines to implement.

Further measures: distroless images or minimal Alpine images drastically cut the number of installed packages and therefore the scanning surface. Multi-stage builds ensure that build tools (compilers, package managers, dev dependencies) never end up in the final production image. The COPY --chown flag sets file ownership correctly right at copy time instead of requiring a later RUN chown, which saves a layer and is clearer in intent. Together with regular Docker image scanning in CI, Dockerfile hardening forms a layered security strategy.

9. Scanning tools compared

Choosing the right Docker image scanning tool depends on requirements. All three leading tools scan OS packages and application dependencies, but they differ in license, depth of integration, and extra features.

Tool License SBOM Standout feature
Trivy Apache 2.0 SPDX, CycloneDX Also scans IaC, K8s manifests, Git repos
Grype Apache 2.0 via Syft Deep Syft integration, policy as code
Snyk Commercial (free tier) CycloneDX Autofix suggestions, web UI, PR integration
Docker Scout Commercial (built-in) Yes Native Docker Desktop/Hub integration
Clair Apache 2.0 No Harbor integration, API first design

For most teams Trivy is the first choice: open source, actively maintained, broad scan coverage and excellent CI integration. Grype is an equally solid alternative when Syft is already in use for SBOM generation. Snyk pays off when the team is willing to pay for autofix suggestions and centralized vulnerability management. Docker Scout is attractive for teams already heavily invested in Docker Hub and Docker Desktop who prefer seamless integration without extra tooling.

Mironsoft

Container security, CI/CD integration and security automation

Docker image scanning not yet in your CI pipeline?

We integrate Trivy or Grype into your CI pipeline, define CVSS thresholds, set up Renovate for automatic base image updates, and put a complete SBOM process in place.

CI integration

Integrate Trivy into GitHub Actions or GitLab CI and configure SARIF reports

SBOM process

Generate SPDX or CycloneDX SBOMs and store them in the registry alongside images

Auto updates

Configure Renovate for Dockerfile updates and set up automerge for patch updates

10. Summary

Docker image scanning in the CI pipeline is the mechanism that keeps known vulnerabilities from slipping into production unnoticed. Trivy is the recommended tool for most teams: open source, easy to integrate, broad scan coverage including SBOM generation. CVSS thresholds combined with a well maintained exception list keep the build from being permanently blocked by unfixable vulnerabilities. Renovate complements the scanning with proactive updates: instead of merely reporting vulnerabilities, it updates base images automatically.

The complete strategy combines reactive scanning (finding CVEs in existing images), proactive hardening (distroless images, non-root users, minimal packages) and automatic updates (Renovate for base images and dependencies). SBOM generation as part of the build process makes it possible to check newly published CVEs against already deployed images without rebuilding them. Together these three building blocks form a layered container security strategy that keeps pace with the evolving threat landscape.

Docker image scanning and security updates: the essentials at a glance

Tool recommendation

Trivy for most teams: open source, simple CI integration, SBOM generation and broad scan coverage including IaC.

Thresholds

CRITICAL with a fix blocks the build. HIGH without a fix raises a warning. Use .trivyignore for known, unfixable CVEs with a reason and review date.

SBOM

Store SPDX or CycloneDX alongside the image in the registry. Enables later checks without a rebuild.

Auto updates

Set up Renovate for Dockerfile updates. Automerge for patch updates, manual review for minor and major.

11. FAQ: Docker Image Scanning and Security Updates in CI

1What is Docker image scanning?
Analysis of a container image for known CVEs in OS packages and application dependencies. Tools compare found packages against NVD and OS vendor advisories.
2When to scan in the CI pipeline?
Right after docker build, before the registry push. Add weekly registry scans on top for newly published CVEs against images already pushed.
3What is Trivy?
Open source vulnerability scanner by Aqua Security. Scans images, IaC, K8s and Git repos. Easy to integrate in GitHub Actions via aquasecurity/trivy-action.
4What is an SBOM?
Software Bill of Materials, a complete package inventory. Enables later CVE checks against deployed images without a rebuild. Important for compliance and incident response.
5Build blocked by unfixable CVEs?
Set ignore-unfixed: true in the Trivy configuration. List known, unfixable CVEs in .trivyignore with a reason and review date.
6Keep base images up to date automatically?
Renovate or Dependabot check Dockerfiles and automatically open PRs. Automerge for patch updates cuts manual effort.
7Which base images have few CVEs?
Alpine images (php:8.4-fpm-alpine) and Google's distroless images. Distroless contains no shell, no package manager, minimal attack surface.
8Trivy vs. Grype?
Both open source, both scan OS packages and app dependencies. Trivy also scans IaC and K8s. Grype integrates more deeply with Syft for SBOM. Equally suited for most teams.
9Show scan results in a GitHub PR?
Run Trivy with format: sarif, then use github/codeql-action/upload-sarif. Results appear in the Security tab and as PR annotations.
10Root or non-root in the container?
Always non-root. USER in the Dockerfile prevents host access with root privileges during a container escape. Most official images already offer a non-root user.