1. What a scanner looks for #
Vulnerabilities, configuration, secrets.
The principle #
A scanner inventories image packages (system and languages: npm, pip, Maven…) and matches them against vulnerability databases (CVEs). Trivy also looks for misconfigurations (Dockerfile, Kubernetes, Terraform) and forgotten secrets.
2. Trivy in practice #
Real results.
Scanning an image #
trivy image --severity HIGH,CRITICAL php:8.2-fpm-alpine
trivy image --ignore-unfixed --severity HIGH,CRITICAL nginx:1.30.6
trivy image --format json -o rapport.json monimage:1.0On a PHP image built in 2023 (Alpine 3.18), Trivy found 23 HIGH and CRITICAL vulnerabilities, all fixed since:
| Package | CVE | Installed | Fixed in |
|---|---|---|---|
| curl | CVE-2023-38545 | 8.3.0-r0 | 8.4.0-r0 |
| curl | CVE-2024-6197 | 8.3.0-r0 | 8.9.0-r0 |
| libcrypto3 | CVE-2023-5363 | 3.1.3-r0 | 3.1.4-r0 |
| libcrypto3 | CVE-2024-6119 | 3.1.3-r0 | 3.1.7-r0 |
Here, the fix is simple: rebuild the image on an up-to-date base.
The noise of unfixed vulnerabilities #
On the latest official nginx image (Debian), Trivy reports 71 HIGH and CRITICAL vulnerabilities, 69 of them with no fix available. Blocking CI on these 69 would lead nowhere: use --ignore-unfixed to keep only what you can fix, and track the rest in a justified .trivyignore file, or switch to a hardened image.
Scanning the configuration too #
trivy config DockerfileTests: 27 (SUCCESSES: 22, FAILURES: 5)
Failures: 5 (UNKNOWN: 0, LOW: 2, MEDIUM: 1, HIGH: 2, CRITICAL: 0)
DS-0001 (MEDIUM): Specify a tag in the 'FROM' statement for image 'node'
DS-0002 (HIGH): Specify at least 1 USER command in Dockerfile with non-root user as argument
DS-0005 (LOW): Consider using 'COPY . /app' command instead of 'ADD . /app'
DS-0026 (LOW): Add HEALTHCHECK instruction in your Dockerfile
DS-0029 (HIGH): '--no-install-recommends' flag is missed: 'apt-get update && apt-get install -y curl'Trivy overlaps with Hadolint (tag, ADD, --no-install-recommends) and adds the missing non-root user and HEALTHCHECK.
3. Blocking in CI, and alternatives #
Automating.
In a pipeline #
name: image
on: [push, pull_request]
jobs:
build-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint the Dockerfile
run: docker run --rm -i hadolint/hadolint:v2.15.1 hadolint --failure-threshold warning - < Dockerfile
- name: Build the image
run: docker build -t app:${{ github.sha }} .
- name: Scan the image
run: |
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.76.2 \
image --exit-code 1 --ignore-unfixed --severity HIGH,CRITICAL app:${{ github.sha }}--exit-code 1 fails the job as soon as a fixable HIGH or CRITICAL vulnerability is found.
Other tools #
| Tool | Strengths |
|---|---|
| Trivy (Aqua) | Vulnerabilities, configuration, secrets, SBOM; free |
| Grype (Anchore) | Fast free scanner, often paired with Syft for SBOM: grype monimage:1.0 |
| Docker Scout | Built into Docker Desktop and Docker Hub, base image recommendations: docker scout cves monimage:1.0 |
| Registries | Harbor (built-in Trivy), GitLab, GitHub: scan on push |
Grype and Docker Scout were not run for this article; their commands come from their documentation.
Sources #
Real results from Trivy 0.76.2, November 2026; counts change daily with vulnerability databases.
