5 min read

Surviving a Week of 9.8 RCEs on a Raspberry Pi: How I Built a Zero-Noise CVE Watchdog with Gemini 4 Argon & AGY

Last week threw three massive RCEs and a Certificate Authority breach at the self-hosting world. Here is how I locked down my Raspberry Pi homelab, eliminated 74 critical sub-dependency CVEs down to zero, and automated the whole security loop in under an hour using Gemini 4 Argon (Medium) in AGY.
Surviving a Week of 9.8 RCEs on a Raspberry Pi: How I Built a Zero-Noise CVE Watchdog with Gemini 4 Argon & AGY
Photo by Kingsley Mkpandiok / Unsplash

If you run your own servers, last week felt less like a normal October week and more like a live fire drill.

Within the span of a few days, the security world got hit from multiple angles at once. First came the PHP2Shell disclosures—a pair of brutal, unauthenticated Remote Code Execution (RCE) vulnerabilities in the core PHP runtime (CVE-2026-109618 and CVE-2026-109619, followed closely by a session upload progress vector) that could trigger memory corruption before a single line of application code even ran. On the exact same day, Node2Shell (CVE-2026-111497) dropped: a critical out-of-bounds write in the Brotli compression decoder bundled directly inside Node.js and system libbrotli libraries, meaning something as routine as decompressing an untrusted HTTP stream could hand over a shell. And just to keep things interesting, a major Certificate Authority breach involving compromised eMudhra intermediate keys forced an emergency update across Cloudflare Tunnel (cloudflared) clients worldwide.

In my previous post, My Cloud, at Home, I wrote about why I moved away from endless SaaS subscriptions to run my own stack on a Raspberry Pi sitting quietly on my desk. Ownership is liberating—until a week like this happens and you realize that you are the security team.

How It Hit My Raspberry Pi

When I started auditing my Pi, there was some immediate good news and some sobering bad news.

The good news: my homelab runs zero PHP. Even my DNS sinkhole had already moved to an embedded C/C++ web server in its modern release, so the PHP2Shell wave bounced right off without a scratch.

The bad news: I wasn't off the hook. Because I keep my router ports closed and route public traffic through Cloudflare Tunnels, my cloudflared daemon was sitting on a version that still trusted the compromised CA chain and had --no-autoupdate enabled. Worse, several of the core web services running in Docker—including my blogging engine, analytics, and monitoring tools—run on Node.js and Alpine/Debian compression libraries that were squarely in the blast radius of the Brotli RCE, alongside a couple of nasty application-level RCEs disclosed this month.

Fixing It Once Isn't Enough

Bumping a few container digests and upgrading a systemd service takes twenty minutes. Anyone can do a one-off patch when Twitter and Hacker News are screaming about a 9.8 CVE.

But reactive firefighting is a trap. What happens next month when a critical vulnerability hits a transitive dependency on a Tuesday night while I'm away from my desk?

At the same time, this is a single Raspberry Pi running a handful of personal services—not a Fortune 500 Kubernetes cluster. I didn't want to overengineer the solution by spinning up a bloated, RAM-hungry security appliance that eats half my board's memory 24/7 just to tell me a package is outdated. I wanted something lightweight, deterministic, and completely silent when everything is healthy, but ruthless the moment a real 9.0–10.0 Critical CVE has a fix available.

The Lightweight Security Stack I Added

Instead of running another permanent background daemon, I split the defense into two zero-idle-memory layers:

  1. Unattended Host & Tunnel Patching (unattended-upgrades): I wired Cloudflare's official APT repository directly into Debian's native unattended-upgrades alongside Debian Security and Raspberry Pi OS updates. Now, if cloudflared, openssl, libc6, or libbrotli gets an emergency patch upstream, the host pulls and applies it automatically via a daily systemd timer—using 0 MB of RAM the rest of the day.
  2. Ephemeral Container Scanning & Auto-Patching (Trivy + Python Orchestrator): For my Docker stack, I added an on-demand Aqua Security Trivy scanner (aquasec/trivy) backed by a persistent vulnerability database volume. It spins up once a night, scans every running container image in about 14 seconds, patches fixable criticals, and immediately exits.

How the Nightly Flow Works (and Avoiding Alert Fatigue)

The hardest part of security automation isn't scanning—it's avoiding alert fatigue while actually fixing the problem. If a scanner emails you the same 50 warnings every morning at 4:00 AM, you'll eventually create a filter and ignore it.

Here is how the nightly pipeline works now:

  • 03:30 AM — Automated Database Snapshots: Before anything else, a cron script dumps and compresses all PostgreSQL and MySQL databases with a 7-day rolling retention.
  • 04:00 AM — The 14-Second Critical Scan: My scanner script inspects all running Docker containers strictly for fixable CRITICAL vulnerabilities (--severity CRITICAL --ignore-unfixed).
  • Automatic In-Place Remediation: When a fixable critical CVE is detected inside a container—whether it's an OS library (apt/apk), a Python package (uv/pip), or a Node.js module (npm)—the script automatically upgrades the vulnerable package inside the container, commits the patched image layer, and immediately re-scans it to verify the fix.
  • Smart State Diffing (seen_cves.json): The script compares findings against a local JSON state file. If everything is clean and nothing changed since yesterday, it sends zero emails.
  • [CVE AUTO-PATCHED] Mailgun Reports: Whenever a critical vulnerability is caught and patched overnight (or if one requires a manual upstream image bump), I wake up to a clean HTML report in my inbox via Mailgun showing the exact container, CVE ID, CVSS score, and a green (AUTO-PATCHED / FIXED) confirmation—plus I can run --status in my terminal anytime to see a live [FIXED / CLEAN] checklist across every service.

The coolest side effect? When we ran the very first deep scan across my 20 containers, Trivy uncovered 74 fixable critical CVEs hiding deep inside upstream base images—things like older gosu entrypoint binaries, outdated Python pillow and certifi wheels, and nested npm packages that upstream maintainers hadn't rebuilt yet. We didn't just mute them: we rebuilt the Go helper binaries with Go 1.25, upgraded the internal virtual environments and packages, and drove the open Critical CVE count from 74 all the way down to 0 across all 20 containers.

Built in One Session with Gemini 4 Argon (Medium) via AGY

What blew me away most wasn't just seeing Open fixable CRITICAL CVEs: 0 across 20 containers—it was how the whole thing came together.

I did this entire audit, live threat research, database backup, multi-container upgrades, in-place image patching, and cron/Mailgun automation in a single interactive session using Gemini 4 Argon (Medium) inside AGY (Antigravity).

Normally, researching three brand-new CVEs, auditing twenty containers, surgery-patching upstream Docker layers, and writing a state-aware Python/Bash auto-patcher and email notifier would easily eat up an entire Saturday afternoon. With Gemini 4 Argon (Medium) in AGY, it felt like pair-programming with a senior security engineer who already knew my docker-compose.yml layout, respected my @sha256 digest pinning, backed up every database before touching a line of config, and didn't stop until every last container reported clean.

Self-hosting is about owning your infrastructure, and AI tooling like AGY + Gemini 4 Argon takes away the tedious maintenance tax while leaving you in full control of the architecture. My Raspberry Pi is still humming quietly on my desk—only now, it watches and patches its own back while I sleep.