Container Vulnerability Scanning in CI/CD: Trivy, Grype, Snyk, and Anchore Compared

Published Updated 18 min read
container securityvulnerability scanningTrivyCI/CDSBOMFalcoDevSecOps

Container vulnerability scanning is the single highest-ROI security control you can add to a CI/CD pipeline. A 2025 Snyk report found that 84% of container images in production contain at least one high or critical vulnerability, and 60% of those were introduced through base images that teams had not updated in over 90 days. Scanning at build time — before images reach production — closes that gap without adding meaningful latency to your pipeline.

This guide compares the four dominant scanners (Trivy, Grype, Snyk, and Anchore), provides production-ready GitHub Actions YAML, covers runtime scanning with Falco, walks through SBOM generation with Syft, and defines a remediation SLA framework your team can adopt immediately.

---

Scanner Comparison: Trivy vs Grype vs Snyk vs Anchore

The right scanner depends on your pipeline speed requirements, language ecosystem, licensing budget, and whether you need enterprise compliance reporting.

CriterionTrivyGrypeSnykAnchore Enterprise

Scan speed (alpine:latest)4-8s6-12s15-30s20-45s
Scan speed (node:20-slim)12-20s18-30s35-60s40-90s
CVE database sourceOSV + NVD + GitHubGrype DB (OSV)Snyk IntelNVD + vendor feeds
Language package coverage20+ languages15+ languages30+ languages20+ languages
SBOM generationYes (CycloneDX, SPDX)Yes (SPDX)Yes (CycloneDX)Yes (SPDX, CycloneDX)
License scanningYesNoYesYes
IaC scanningYesNoYesNo
Secret detectionYesNoYesNo
CI/CD integrationGitHub Actions, GitLab, Jenkins, CircleCIGitHub Actions, GitLabGitHub Actions, GitLab, Jenkins, 20+GitHub Actions, GitLab, Jenkins
PricingFree (open source)Free (open source)Free tier + paid plans from $98/moEnterprise pricing (~$25K+/yr)
False positive rateLowLowMediumLow
Policy-as-codeYes (OPA)NoYesYes
Compliance reportsNoNoYes (SOC 2, ISO 27001)Yes (PCI DSS, HIPAA, CIS)

Recommendation by use case:

  • Startups and open-source projects: Trivy — fastest, zero cost, broadest coverage
  • Developer-first security: Snyk — IDE plugins, PR comments, actionable fix guidance
  • Enterprise compliance: Anchore Enterprise — policy engines, audit trails, regulatory reports
  • Lightweight supplemental scanning: Grype — pairs well with Trivy for cross-validation

---

GitHub Actions Integration: Production-Ready Trivy Workflow

The following workflow scans on every pull request and push to main, fails the build on critical vulnerabilities, and uploads results to GitHub Security tab via SARIF.

<h1>.github/workflows/container-scan.yml</h1>

name: Container Security Scan

on:

push:

branches: [main, staging]

pull_request:

branches: [main]

env:

REGISTRY: ghcr.io

IMAGE_NAME: ${{ github.repository }}

jobs:

build-and-scan:

name: Build and Vulnerability Scan

runs-on: ubuntu-latest

permissions:

contents: read

packages: write

security-events: write

steps:

- name: Checkout repository

uses: actions/checkout@v4

- name: Build Docker image

run: |

docker build -t ${{ env.IMAGE_NAME }}:${{ github.sha }} .

# Trivy filesystem scan (pre-build, catches dependencies early)

- name: Trivy filesystem scan

uses: aquasecurity/trivy-action@master

with:

scan-type: fs

scan-ref: .

severity: HIGH,CRITICAL

exit-code: 0 # Warn only on filesystem scan

format: table

# Trivy image scan (post-build, catches base image CVEs)

- name: Trivy image scan

uses: aquasecurity/trivy-action@master

with:

image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }}

format: sarif

output: trivy-results.sarif

severity: CRITICAL,HIGH

exit-code: 1 # Fail build on CRITICAL

ignore-unfixed: true

vuln-type: os,library

- name: Upload SARIF to GitHub Security tab

uses: github/codeql-action/upload-sarif@v3

if: always() # Upload even on scan failure

with:

sarif_file: trivy-results.sarif

# Generate SBOM for audit trail

- name: Generate SBOM with Syft

run: |

curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

syft ${{ env.IMAGE_NAME }}:${{ github.sha }} \

-o cyclonedx-json=sbom.cdx.json \

-o spdx-json=sbom.spdx.json

- name: Upload SBOM artifacts

uses: actions/upload-artifact@v4

with:

name: sbom-${{ github.sha }}

path: |

sbom.cdx.json

sbom.spdx.json

retention-days: 90

- name: Push image if scan passes

if: github.ref == 'refs/heads/main'

run: |

echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin

docker tag ${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

---

Base Image Selection: Security Criteria

The base image accounts for 60-80% of all container vulnerabilities. Choosing the right base image is the highest-leverage security decision you make before your application code runs.

Base ImageVuln Count (typical)SizeUse CaseNotes

ubuntu:24.0480-12078 MBGeneral purposeLarge attack surface
debian:12-slim40-7075 MBGeneral purposeBetter than ubuntu
alpine:3.200-57 MBProduction appsmusl libc compatibility check required
distroless/static02 MBGo static binariesNo shell, no package manager
distroless/base0-220 MBDynamically linked appsMinimal glibc only
distroless/nodejs223-8110 MBNode.js appsNo npm, no shell
chainguard/node0-295 MBNode.js productionSBOM and provenance included
chainguard/python0-260 MBPython productionRegularly rebuilt with patches

Multi-stage build pattern (most secure approach):

<h1>Build stage: use full image for compilation</h1>

FROM node:22-slim AS builder

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

RUN npm run build

<h1>Runtime stage: use minimal image</h1>

FROM gcr.io/distroless/nodejs22-debian12

WORKDIR /app

COPY --from=builder /app/dist ./dist

COPY --from=builder /app/node_modules ./node_modules

USER nonroot

EXPOSE 3000

CMD ["dist/server.js"]

---

Runtime Scanning with Falco

Build-time scanning misses runtime attacks: container escapes, cryptomining injected via compromised npm packages, and lateral movement using legitimate binaries. Falco provides kernel-level behavioral detection for these threats.

<h1>falco-rules-custom.yaml — add to /etc/falco/rules.d/</h1>

<ul><li>rule: Unexpected Outbound Network Connection</li>

</ul> desc: Detects unexpected outbound connections from container

condition: >

outbound and container and

not fd.sip in (allowed_outbound_ips) and

not proc.name in (allowed_network_processes)

output: >

Unexpected outbound connection (user=%user.name command=%proc.cmdline

connection=%fd.name container=%container.name image=%container.image.repository)

priority: WARNING

tags: [network, container]

<ul><li>rule: Shell Spawned in Container</li>

</ul> desc: Detects shell execution inside a running container

condition: >

spawned_process and container and

proc.name in (shell_binaries) and

container.name != "debug-container"

output: >

Shell spawned in container (user=%user.name container=%container.name

image=%container.image.repository shell=%proc.name parent=%proc.pname)

priority: CRITICAL

tags: [shell, container, mitre_execution]

<ul><li>rule: Cryptominer Execution</li>

</ul> desc: Detects common cryptomining process patterns

condition: >

spawned_process and container and

(proc.name in (cryptominer_binaries) or

proc.cmdline contains "--mining-threads" or

proc.cmdline contains "stratum+tcp")

output: >

Cryptominer detected (command=%proc.cmdline container=%container.name)

priority: CRITICAL

tags: [cryptomining, container]

---

SBOM Generation with Syft

A Software Bill of Materials (SBOM) is a machine-readable inventory of every dependency in your container. When a new CVE drops (like Log4Shell), an SBOM lets you answer "are we affected?" in seconds rather than hours.

<h1>Install Syft</h1>

curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

<h1>Generate SBOM in multiple formats</h1>

syft myapp:latest -o cyclonedx-json=sbom.cdx.json # For Dependency-Track

syft myapp:latest -o spdx-json=sbom.spdx.json # For legal/compliance

syft myapp:latest -o table # Human-readable summary

<h1>Cross-check SBOM against vulnerability database with Grype</h1>

grype sbom:sbom.spdx.json --fail-on high

<h1>Attest SBOM to image with cosign (supply chain integrity)</h1>

cosign attest --predicate sbom.cdx.json \

--type cyclonedx \

myapp:latest

---

Remediation SLA Framework

Scanning without enforced remediation timelines is theater. Define SLAs before your first critical CVE hits production.

Vulnerability Severity Response Table

CVSS ScoreSeveritySLA — ProductionSLA — StagingSLA — DevImmediate Action

9.0-10.0Critical24 hours48 hours72 hoursPage on-call, freeze deployments
7.0-8.9High7 days14 days30 daysCreate P1 ticket, assign owner
4.0-6.9Medium30 days60 days90 daysAdd to sprint backlog
0.1-3.9Low90 days90 daysNext quarterTrack in vulnerability register
N/AInformationalBest effortBest effortBest effortLog and review

Enforcement automation:

<h1>.trivyignore — track accepted risks with expiration</h1>

<h1>Format: CVE-ID exp:YYYY-MM-DD reason:...</h1>

CVE-2023-44487 exp:2026-06-01 reason:mitigated-by-nginx-rate-limit

CVE-2024-21626 exp:2026-04-15 reason:non-exploitable-no-volume-mounts

Arxentra's managed container platform supports on-demand base image updates through a manual runtime image override, letting you patch OS-layer CVEs without rebuilding your full pipeline. See Arxentra container services for how the runtime image override integrates with your deployment pipeline, and review the platform security overview for compliance reporting options.

---

Pipeline Integration Checklist

  • Scan on every PR (not just merge to main)
  • Gate on CRITICAL severity with exit-code 1
  • Upload SARIF to GitHub Security tab for developer visibility
  • Generate and store SBOM per image SHA
  • Set .trivyignore review cadence (monthly minimum)
  • Enable Falco runtime rules in staging before production
  • Run Syft + Grype cross-validation weekly on production images
  • Review SLA compliance metrics monthly in security review

Container security is a continuous process, not a one-time gate. Teams that automate scanning, enforce SLAs, and layer runtime detection reduce mean time to remediation by 67% compared to manual processes (Snyk State of DevSecOps, 2025). Start with Trivy in CI, add Falco in production, and generate SBOMs from day one — your future self auditing a critical CVE will thank you.