Published 2026-04-25 · 10 min read

The patching gap: why monthly cycles aren't enough for self-hosted services

apt upgrade doesn't touch Plex. Or Jellyfin. Or Grafana, Pi-hole, Sonarr, Radarr, Portainer, the rest of the services that make a homelab actually useful. Most homelab operators have a monthly distro patch cycle and assume that covers everything — it covers maybe 40% of the running software. This is the patching gap, and ignoring it is how modern homelabs get compromised.

What apt upgrade actually patches

Run apt list --installed on a typical homelab box. It returns 1,500–3,000 packages: the Linux kernel, libc, openssl, openssh, systemd, every shared library, and whatever distro-packaged daemons you installed (nginx, postgresql, etc.). When a CVE is disclosed against any of those, the distro maintainers backport a fix and push it through the security repos. apt upgrade picks it up. This pipeline is genuinely excellent and, for the software it covers, is the gold standard.

But that 1,500–3,000 number doesn't include:

Software outside distro repos

Plex / Jellyfin / Emby

Installed via vendor-provided .deb / .rpm from plex.tv/downloads, jellyfin.org/downloads, etc. Each ships its own auto-update mechanism (or doesn't), and those updates are independent of apt upgrade. Jellyfin had multiple critical authentication bypasses across 2023–2024; operators on stale versions remained vulnerable for months.

Grafana / Prometheus / monitoring stack

Most homelab operators install Grafana via grafana.com/oss's repo, which IS part of apt after configuration — but it's a third-party repo, and the cadence is set by Grafana Labs (not your distro's security team). Grafana 8.5 had CVE-2022-31097 (XSS in the alerting module) that wasn't patched in some downstream packages until weeks after upstream.

The *arr suite

Sonarr, Radarr, Lidarr, Readarr, Prowlarr — all installed via Mono / .NET runtimes from custom repos. Each has its own update mechanism. The *arr suite is a poster child for the patching gap: huge install base, security history including credential leakage and SSRF bugs, and almost nobody applies updates promptly.

Docker images

Anything you run as docker pull foo:latest + docker run. The container's contents are independent of the host's apt. The image you pulled six months ago might run an openssl from 2022 with five known CVEs unpatched. apt upgrade on the host doesn't help; you need docker pull foo:latest again, then docker stop && docker run. Most homelab Docker stacks don't refresh images proactively.

Pi-hole, AdGuard, Mikrotik, UniFi

Each has its own update channel. Pi-hole's pihole -up covers Pi-hole + its bundled tooling. Mikrotik's RouterOS updates via the device UI. UniFi Controllers ship .deb but with their own apt repo. None of these are in the distro security feed.

Anything you compiled from source

That git clone && make install you did to get the latest version of a tool that wasn't in apt's repos? It's now stale forever unless you remember it exists. Operators rarely do.

End-of-life packages your distro hasn't dropped yet

A subtler version of the gap: the distro DOES ship a package and DOES still update it, but the upstream version is past end-of-life and no longer gets fixes. Examples:

The disclosure-to-patch lag for the gap

For distro-packaged software, the gap between upstream disclosure and distro-shipped patch is usually 0 to 24 hours. For non-distro software, the gap is whatever the operator's reaction time is — typically days to weeks to months.

The asymmetry is what attackers exploit. Disclosure of a CVE in (say) Plex means:

The operators who escape are either (a) on auto-update for every service, or (b) running a CVE scanner that surfaces "Plex on this host is version X, latest is Y" the morning after disclosure.

Why a CVE scanner catches the gap when apt upgrade can't

A CVE scanner doesn't care which package manager installed something. It reads the binary's reported version (via plex --version, the binary's metadata, or HTTP headers from the running daemon) and matches against the CVE feed. For Plex, the scanner sees "Plex Media Server 1.29.0.6244-819124617" running on port 32400, looks up the CVE feed for plexinc:plex_media_server, and reports any matches.

apt upgrade sees nothing because Plex isn't an apt package on most installs. The CVE scanner sees what's actually running.

Closing the gap without becoming a full-time updater

Five practices, ordered by ROI:

1. Auto-update everything that supports it

Most modern self-hosted software has an auto-update mechanism. Plex updates itself by default. Jellyfin via its package's hooks. Pi-hole via pihole -up cron. Docker images via Watchtower (with caveats — it WILL break things that need a config migration). Each auto-update you enable is one fewer manual touch per CVE.

Caveat: auto-update without testing means a broken release breaks your service silently. For things you don't watch regularly (the *arr suite, downloaders), this is fine. For things you depend on (DNS, SSO, reverse proxy), consider a 24h delay window so you can intervene if a release ships broken.

2. Subscribe to the security mailing lists

For software you can't auto-update but is critical (UniFi Controller, Mikrotik, pfSense, anything in your network path), subscribe to the project's security announce list. That's free and gets you notified day-zero. Practical, low maintenance.

3. Run a CVE scanner against the running fleet

For everything else — the long tail of services that don't auto-update and aren't in any mailing list you watch — a scanner that reads installed-version-from-binary and compares against the feed is the only sustainable answer. Daily scans catch things within ~24h of disclosure even without your active attention.

4. Keep a "what's actually running" inventory

Half the patching gap problem is forgetting what you've installed. A periodic scan (or a manual quarterly review) that lists every running service across every host catches the test installations, the abandoned-but-still-running Docker containers, the helper scripts a former housemate set up. You can't patch what you've forgotten about.

5. Decommission ruthlessly

The single biggest patching gap reducer is having less software running. Every service installed "to play with it" that you forgot about is a chunk of code receiving no attention while accruing CVEs. Quarterly: list everything, kill anything not actively used. The lab gets smaller and the patch surface shrinks proportionally.

What Noxen does for the patching gap

Noxen scans installed binaries, not just apt-managed packages. The CVE matcher reads version strings from package managers AND from running services (HTTP banner, executable --version output where available). When a finding fires for Plex 1.29 with CVE coverage, you see it in the morning report regardless of whether Plex came from apt, the vendor's deb, a Docker image, or a manual install.

The exposed-admin-surface probe complements this — it detects the panels you forgot you'd exposed, not just the versions of the panels you remember. Running both nightly gets you closest to "I know what's actually running on my fleet" without becoming a full-time updater.

$79 one-time at launch.