Trivy, a deceptively simple scanner, reveals that most "secure" Helm charts are actually ticking time bombs of known vulnerabilities.

Let’s see it in action. Imagine you’ve got a Helm chart for a simple Nginx deployment.

# First, install Trivy if you haven't already
# (See Trivy's official docs for installation instructions)

# Scan the Helm chart directory directly
trivy fs ./my-nginx-chart

Here’s what you might see:

my-nginx-chart/templates/deployment.yaml (nginx)
-----------------------------------------------
Total: 1 (UNKNOWN)

my-nginx-chart/Chart.yaml (nginx)
---------------------------------
Total: 1 (UNKNOWN)

my-nginx-chart/values.yaml (nginx)
----------------------------------
Total: 1 (UNKNOWN)

my-nginx-chart/templates/service.yaml (nginx)
---------------------------------------------
Total: 1 (UNKNOWN)

Wait, that’s not right. It’s saying "UNKNOWN" for everything, which is Trivy’s way of saying it found something but couldn’t categorize it as a specific vulnerability in a known package. This often happens when Trivy analyzes the files themselves (like YAML templates) rather than the packages those templates will deploy.

To actually find vulnerabilities in the software your Helm chart installs, Trivy needs to look at the container images specified in your chart. This is where the real power lies.

# Tell Trivy to scan the Helm chart and analyze the referenced container images
trivy helm ./my-nginx-chart

Now, the output changes dramatically. Trivy renders your Helm chart, substituting values.yaml into your templates, and then scans the resulting container images for known CVEs.

nginx:0.1.0 (app/nginx)
=======================
Total: 114 (UNKNOWN)

CVE-2023-XXXX: Medium
  Description: ...
  Installed Version: 1.23.4
  Fixed Version: 1.24.0
  References: ...

CVE-2022-YYYY: High
  Description: ...
  Installed Version: 1.23.4
  Fixed Version: 1.23.5
  References: ...

... (many more findings) ...

This output is gold. It tells you the specific CVEs found, their severity, the version you have installed, and crucially, the version that fixes the vulnerability.

The mental model for Trivy and Helm is this:

  1. Helm Templating: Helm is a package manager. It uses Go templating to turn generic chart definitions into Kubernetes manifests specific to your environment, using your values.yaml file.
  2. Image Discovery: Trivy, when run with trivy helm, simulates this templating process. It figures out which container images are being deployed by your chart based on the rendered manifests.
  3. Image Scanning: Once Trivy knows the images, it pulls them (or uses cached layers) and scans their contents for operating system packages and application dependencies that have known vulnerabilities.

The most surprising thing is how often charts rely on outdated base images or specific package versions within those images that have long-standing, publicly known vulnerabilities. You might have a perfectly valid values.yaml, but if your Chart.yaml or templates/deployment.yaml specifies an image tag like nginx:latest or ubuntu:20.04, you’re inheriting whatever vulnerabilities that image has at that moment.

To effectively use this, you need to understand the Fixed Version field. When Trivy reports a vulnerability, it often suggests a newer version of the package that contains the fix. For container images, this usually means updating the image tag to a version that uses the patched package. For example, if Trivy says nginx:1.23.4 has a vulnerability fixed in 1.24.0, you’d look for an nginx:1.24.0 image (or a later patched version) and update your values.yaml or deployment.yaml accordingly.

The next common problem you’ll encounter is dealing with vulnerabilities in application dependencies within your container image that aren’t fixed by simply updating the base image tag.

Want structured learning?

Take the full Helm course →