Haydn Cowley

Write-ups

I scanned my own apps for vulnerabilities. The first run found 2 critical

After the PHP alert I wanted to catch old, vulnerable software inside my Docker apps without waiting for a warning. The first scan found 17 serious problems in my own dashboard and speed tester.

3 min readBy Haydn
Goal
Check every Docker app on the Pi for known vulnerabilities, every week, automatically
Result
2 critical, 15 high down to 0 critical, 6 high
Tools
Trivy, Docker, ntfy

Why I did it

The NCSC PHP alert taught me that a Docker app brings its own software with it. My Speedtest container had an old PHP inside, and I only found out because the NCSC published a warning. I wanted to find problems like that myself, before anyone told me.

What Trivy does

Trivy is a free scanner. It looks inside a Docker image, lists every package and library in it, and checks them against public databases of known vulnerabilities (CVEs and GitHub security advisories).

I set it to only count HIGH and CRITICAL problems that already have a fix. A scanner that reports hundreds of things you can't do anything about just gets ignored, so every result has to be something I can act on.

# what my script runs for each app
$ trivy image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed <image>

The first scan

# the summary my script saves, per app
homepage           2 critical, 13 high
speedtest-tracker  0 critical, 2 high
total              2 critical, 15 high

Both critical ones were in my Homepage dashboard, in libraries the app is built from. I hadn't updated it since I set it up, so it was running old versions. Jellyfin wasn't in the list because it's installed straight on the Pi, not in Docker, so it gets its fixes from my automatic security updates instead.

Getting the numbers down

The fix was to pull the newest images, restart the apps and scan again to prove it worked:

$ sudo docker compose pull
$ sudo docker compose up -d
$ sudo homelab-trivy
# the new summary
homepage           0 critical, 4 high
speedtest-tracker  0 critical, 2 high
total              0 critical, 6 high

Updating fixed both critical problems and 9 of the high ones. The 6 left have fixes in the libraries, but the people who make Homepage and Speedtest haven't released new images with them yet. There's nothing more I can safely do except wait, so I'm watching them instead.

How bad was it?

Lower than the numbers sound. Both apps are only reachable from my home network and over Tailscale, never from the internet, so an attacker would already need to be inside my network. But "only reachable from inside" isn't a reason to leave known holes open, especially when fixing it took one command.

Making it automatic

  • It runs every Monday morning from cron and sends the result to my phone with ntfy, the same app that tells me if a service goes down. A critical result comes through as a high-priority alert.
  • The result shows on my live lab and status page as "Vulnerability scan", and on my private dashboard.

What went wrong

Installing Trivy failed with "repository is not signed", which sounds scary. The real error was further up: Permission denied on the signing key. My Pi makes new files readable by root only, and apt checks signatures as a different user, so it couldn't read the key. chmod 644 on the key fixed it.

What I learned

  • Docker images go out of date silently. Nothing tells you unless you check.
  • Filtering to "fixable, high and critical" makes a scan useful instead of overwhelming.
  • Always scan again after a fix. The second scan is the proof.
  • Read the whole error, not just the last line.

How I used AI: Claude wrote the scan script and tested it against fake results before it went on the Pi. I installed Trivy, ran the scans, updated the apps and checked the results. The full, unedited notes are in my build log.