Trivy EP06 | Fix Vulnerabilities in Local Docker Images Using Trivy | Real World Hands On Demo
Local vulnerability scanning and remediation represent the first line of defense in a DevSecOps pipeline. By identifying and patching security flaws directly on your development workstation before pushing artifacts to remote registries like Docker Hub, engineering teams prevent critical vulnerabilities from reaching downstream staging and production environments.
1. The DevSecOps Shift-Left Philosophy
Why Do We Need Local Scanning?
In traditional software development lifecycles, security scans often occurred late in the pipeline—frequently right before production deployment or even post-deployment. This late-stage discovery creates significant friction:
- High Remediation Costs: Fixing a security flaw discovered in production requires code rollbacks, emergency patching, and redeployment cycles.
- Context Loss: The developer who wrote the vulnerable code may have moved on to other tasks.
- Pipeline Blockages: Failed security gates halt delivery pipelines, frustrating both developers and operations teams.
The Shift-Left Mental Model
The "Shift-Left" approach moves security checks as close to the developer's keyboard as possible.
By integrating tools like Trivy into local development workflows, developers catch dependency vulnerabilities, outdated package managers, and base image flaws while actively writing code.
2. Setting Up a Vulnerable Python Environment
To demonstrate local vulnerability identification and remediation, we construct a deliberately unpatched Python application container.
Step 1: Create a Working Directory
mkdir python-demo
cd python-demo
Step 2: Write a Basic Application (app.py)
Create a simple Python script that serves as our application entry point:
# app.py
print("Hello there!")
Step 3: Write the Initial Dockerfile
Create a Dockerfile utilizing an older or standard Python base image that installs Flask and executes our application:
FROM python:3.10-slim
RUN pip install Flask
COPY app.py .
CMD ["python", "app.py"]
Step 4: Build the Local Docker Image
Build the container artifact and tag it appropriately for our baseline scan:
docker build -t app-with-issue:latest .
3. Executing the Trivy Scan and Analyzing Results
With our local image built, we execute Trivy to inspect its contents against known vulnerabilities.
Running Trivy with Performance Timing
We use the Linux time utility in conjunction with the trivy image command to measure how long the scan takes:
time trivy image app-with-issue:latest
Note: Trivy downloads and updates its local vulnerability database—synthesizing data from multiple security advisories and CVE feeds—before performing the scan. Subsequent scans leverage this cached database for significantly faster execution.
Analyzing Scan Output
Upon executing the scan, Trivy inspects both the operating system packages and language-specific package managers (such as pip for Python).
The scan output reveals a medium-severity vulnerability residing within the Python package manager (pip):
- Package Manager:
pip(Python Package Index installer) - Installed Version:
23.0.1 - Fixed Version:
23.3(or latest patched release) - Vulnerability ID: Associated CVE identifier linking to Aqua Security advisory documentation.
Actionable Intelligence in Trivy Reports
Trivy provides direct references for each detected vulnerability:
- Advisory Links: Direct URLs to Aqua Security database entries providing deep technical context.
- CVE Identifiers: Standardized vulnerability codes that can be researched across public databases (e.g., NVD).
- Exact Version Metrics: Precise identification of what version introduced the flaw and which minimum version contains the official security patch.
4. Step-by-Step Remediation of the Vulnerability
Fixing application-level or package-manager-level vulnerabilities at the local level requires modifying the build recipe (Dockerfile) rather than attempting manual overrides inside a running container.
Step 1: Backup the Original Dockerfile
For comparison and auditing purposes, preserve our original configuration:
cp Dockerfile Dockerfile.issue
Step 2: Update the Dockerfile with the Security Patch
Modify the Dockerfile to upgrade pip to a secure version during the build process before application dependencies are resolved:
FROM python:3.10-slim
# Upgrade pip to mitigate known package manager vulnerabilities
RUN pip install --upgrade pip
RUN pip install Flask
COPY app.py .
CMD ["python", "app.py"]
Step 3: Rebuild the Container Image
Build the updated image with a new tag:
docker build -t app-with-fix:latest .
Step 4: Verify the Fix with Trivy
Run Trivy once more against the freshly built, patched image:
trivy image app-with-fix:latest
Result: The specific pip vulnerability is successfully resolved. Any remaining lower-level findings (such as underlying Debian OS package vulnerabilities) belong to the base operating system layer.
5. Division of Responsibility: Application vs. Infrastructure
In containerized architectures, vulnerability management is shared between developers and infrastructure/platform teams:
6. Summary and Key Takeaways
- Shift-Left Security: Scanning local images before pushing to container registries saves time, reduces remediation costs, and stops vulnerabilities before they reach production.
- Trivy Database: Trivy relies on a robust, multi-source vulnerability database that aggregates security advisories and CVE feeds.
- Measuring Scan Performance: Utilizing the
timecommand helps benchmark scan durations, particularly when accounting for initial database updates. - Package Manager Flaws: Language-specific package managers like
pipcan harbor vulnerabilities that are easily patched by adding an explicit upgrade command (pip install --upgrade pip) inside theDockerfile. - Reproducible Builds: Baking security fixes directly into the
Dockerfileensures that every subsequent build inherits the patch automatically. - Separation of Concerns: Developers fix application and package-level issues, while infrastructure teams manage base operating system vulnerabilities.
- Pre-Registry Verification: Local verification ensures that artifacts pushed to public or private registries (like Docker Hub) maintain a clean security posture.