warden is my homelab security console — it reads the logs my WAF can't see, scans the boxes, watches my AI agents, and proposes bans and patches I approve with a ✅ in Discord. It never does anything on its own. I wrote up what it does before; this is about the cleanup I just did, because it had got messy.
It had grown 16 tabs
Every time I added something — incidents, agent tracking, vulnerabilities, endpoint integrity — it got its own tab. Dashboards grow like that. One day I counted and it was 16 tabs across four groups, and I realised I was hunting for things I used every day.
So I cut it down to 6:
- Overview — the dashboard
- Review — the one place for everything waiting on my ✅ / ❌
- Threats — detections, edge, network, incidents, geo
- Agents — what my AI agents are reaching out to
- Posture — attack surface, vulnerabilities, endpoints, health
- Settings
The related views sit under a little sub-nav inside each tab, so nothing's gone — it's just one click deeper. And instead of a scary number on every tab, a parent tab shows a small dot when something inside actually needs me. The real counts live where they make sense, so I don't get a meaningless "512" on a tab that's really just counting known CVEs.
The small things that were quietly annoying
- The settings page listed raw config keys like
patch.expire_hoursandcloudflare.zone_id. Now each field has a plain label ("Approval expires after (hours)", "Cloudflare Zone ID") with the raw key dimmed underneath, so I still know what maps to the config file. - API tokens and the "how do I connect a tool" bits were off on their own. They live under Account now, where I'd actually look for them.
- The approvals queue used to sit on top of the Settings page. It's its own Review tab now.
The bit that mattered: my database was world-readable
While I was in there I checked how warden stores anything sensitive. Most of it was already fine — API tokens are only kept as a SHA-256 hash, passwords are scrypt, session cookies are random and only their hash is stored, and actual secrets (bot tokens, API keys) never touch the database at all.
Then I looked at the file permissions on the database itself. 644. World-readable.
On a shared box that's a real problem: the database holds logs, session hashes, and — if you use warden's own 2FA — the TOTP seed. Anything else running on that machine as another user could just read it. In my case that includes the sandboxed coding agent I let loose on my repos, which is exactly the kind of thing warden exists to keep honest.
Fix was simple but I made it stick: warden now forces the database (and its write-ahead files) to 0600 on every start, and each process sets a umask so anything it creates is owner-only from birth. I tested it by deliberately setting it back to 644 and restarting — it put itself straight back to 600.
The lesson I keep relearning: the dangerous gaps aren't the exotic ones. It was a default file permission sitting there the whole time.
Get it
It's on GitHub, AGPL-3.0, dependency-free Python — it'll run on a Pi. The v3.2 release has the full changelog, and there's a 5-minute demo setup if you want to click around before wiring it to anything.
Still detect-only and read-only by default. It tells me what it'd do; I decide.

Top comments (0)