Noticing automatically when a site's security slips
A small robot that checks my websites every 30 minutes and flags any security setting that has quietly disappeared.
The need
A security setting removed by mistake during an update is invisible — until an audit, or a customer, notices it.
The idea
Don't rely on remembering to check. Make the check run by itself, apart from what it watches, so one outage can never hide another.
What I built
- A checker for the standard protections a website should send: five security headers, the switch to HTTPS, cookie settings, and certificate expiry with a three-week warning.
- It runs on its own schedule, outside the websites, and stores its history in its own database.
- A private dashboard, behind an authentication gate.
The result
- 30 minbetween two checks
- 5security headers verified on every pass
- 3 weekswarning before a certificate expires
- 30 Aug 2026in service since
On its first pass it found a header revealing the version of the framework in use — fixed within the hour. Then it caught its own mistake: its first dashboard was public and listed in the sitemap, effectively a map for attackers. It was closed the same day and reopened behind authentication.
In pictures
What I learned
A security tool must pass its own test first. A monitoring tool that publicly shows what it monitors becomes a reconnaissance tool for anyone who finds it.
Technical details Stack, architecture and decisions — for technical readers
Stack
- Node.js (no npm dependency)
- Express
- SQLite (node:sqlite)
- systemd timer
- Cloudflare Access
How it works
- Checks: presence of CSP, HSTS, X-Frame-Options, X-Content-Type-Options and Referrer-Policy; no Server or X-Powered-By leak; Secure and HttpOnly on every cookie; HTTP → HTTPS redirect; TLS certificate not expiring within three weeks.
- Zero npm dependency — Node built-in modules only.
- Decoupled by design: the checker is a systemd service triggered every 30 minutes that writes to its own SQLite database; the dashboard only reads that database and never runs a check itself.
- After the self-inflicted exposure: dashboard removed from the sitemap and robots.txt, service identifiers moved out of the source code, then reopened only behind Cloudflare Access on a dedicated subdomain.
Still missing
- Dashboard not public — by design