How to Fix a Trivy CVE Vulnerability in requirements.txt

Trivy scans your source tree and exits non-zero on a CRITICAL CVE in a pinned dependency - the Fixed Version column in its output tells you exactly what to change. Bump the pin in requirements.txt and the gate passes.

DevOps Engineertrivycvesecurity

How Trivy's filesystem scan works

trivy fs walks your project files looking for dependency manifests (requirements.txt, go.sum, package-lock.json, etc.) and cross-references every version against the NVD/OSV advisory database. With --exit-code 1 and --severity CRITICAL, it returns a non-zero exit code the moment it finds a CRITICAL-severity CVE - which is the standard CI gate pattern.

# See the full finding with the Fix Version column
trivy fs --severity CRITICAL .

# CI gate - exits 1 if any CRITICAL is found, exits 0 if clean
trivy fs --severity CRITICAL --exit-code 1 .

The output table has five columns: Library, Vulnerability, Severity, Installed Version, and Fixed Version. The Fixed Version column is the source of truth - it tells you the minimum patched release.

Reading the finding

A typical CRITICAL finding looks like this:

requirements.txt
================
Library   Vulnerability    Severity  Installed  Fixed
--------- ---------------- --------- ---------- -------
pyyaml    CVE-2020-14343   CRITICAL  5.3.1      5.4

CVE-2020-14343 is an arbitrary code execution vulnerability in PyYAML's FullLoader - it deserializes arbitrary Python objects from untrusted YAML input. It was patched in 5.4 by restricting the default loader.

Fixing it: bump the pin

Open requirements.txt and update the vulnerable line. A range pin is fine; an exact pin is more reproducible:

# before
pyyaml==5.3.1

# after - range is acceptable
pyyaml>=5.4

# or pin the exact patched release for full reproducibility
pyyaml==5.4.1

Re-run the gate:

trivy fs --severity CRITICAL --exit-code 1 .
# exit code 0 - no CRITICAL findings

Why this pattern matters in CI

The hard part of dependency CVE management is not the one-line fix - it is making the gate fail CI reliably so old pins cannot drift back in. Once trivy fs --exit-code 1 is in the pipeline:

To automate bumps, layer Renovate or Dependabot on top: they open PRs whenever a newer patched version is available, so you review and merge rather than hunt manually.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do I find what version fixes a CVE in Trivy's output?

Run trivy fs --severity CRITICAL . and read the Fixed Version column in the output table. That column names the minimum patched version - pin to that or any higher release.

Why does Trivy exit with a non-zero code in CI?

The --exit-code 1 flag tells Trivy to return a non-zero exit code when it finds any finding at or above the specified severity. This is the standard way to fail a CI pipeline on a CRITICAL CVE.

Is a range pin like pyyaml>=5.4 safe, or should I use an exact version?

A range pin clears the CVE gate immediately and automatically takes the next patched release. An exact pin is more reproducible. Both are valid - many teams use a range for quick unblocking and then pin exact in a follow-up PR.

Keep learning

Fix the Nginx 502 Bad GatewayDevOps projectRecover a Crashed Linux ServiceDevOps projectCorrect a Postgres Port MismatchDevOps projectDevOps roadmapStep by step to hiredDevOps interview questionsSTAR answersAll DevOps projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →