Purpose: Make the VeriPath infrastructure resilient against malware and
intrusion — not by automated scanning alone, but through layered prevention,
scheduled detection that someone actually reads, a rehearsed response, and a
daily human operating rhythm that is reminded and enforced.Trigger: Security incident 2026-08-03 → 2026-08-14 (Forgejo compromise,
Kinsing crypto-miner botnet). See
Root Cause & Remediation
and Hosting Provider Complaint.Owner: Matthew (final sign-off) · Maintained by: Hermes (docs/rhythm)
- OpenCode (implementation) · Version: 1.0 (2026-08-15)
The Forgejo breach was active for 11 days (03–14 Aug) and was first
reported to us by our hosting provider, not by our own monitoring. The
post-mortem identified five root causes:
| # | Failure | Lesson |
|---|---|---|
| 1 | Forgejo 14.0.5 ran for months with a known RCE (fix only in 15.x/16.x) | Patch cadence + advisory tracking are mandatory |
| 2 | Registration was left open | Close standing exposure by default |
| 3 | Port 3000 bound to 0.0.0.0 | Public web ports only via reverse proxy on localhost |
| 4 | 08-11 containment killed processes but not the entry vector | Containment must close the VECTOR, not just the symptoms |
| 5 | No egress control — container phoned home + scanned 2.9M IPs | Containers get least-privilege networks too |
| 6 | Detection relied on accident (Fasthosts complained) | Scheduled scanning only counts if someone reads the output daily |
| 7 | esocket5 misread as AI workload |
Know your own workloads; treat anomalies as hostile until proven otherwise |
Operating principle: we do not rely on any single layer. Tools find;
people decide; rhythm keeps both honest.
cap_drop: ALL,/tmp, resource limits, and egress network/root/.config //root/forensics/backup-style restricted files, NEVER in the wiki, chat,integrations/lynis_parser.py) anddefectdojo_push.sh exists). Trivy/nmap/ZAP findings land here, withApplied patch to hooks, new users on Keycloak during non-work.fadea* / ksmd / javab / bob2 / esocket* IoCs/root/forensics/| Control | Status | Owner |
|---|---|---|
| Forgejo 16.0.2, registration off, port→localhost | ✅ DONE (14 Aug) | OpenCode |
| Credentials rotated (Forgejo DB, tokens, webhook) | ✅ DONE | OpenCode |
| Host sshd + fail2ban + cpu-guard fix | ✅ DONE (15 Aug) | OpenCode |
| client_db 194.164.18.33 localhost bind | ✅ DONE | OpenCode |
| Forgejo admin 2FA (matthew, studio) | ⏳ OPEN — user action | Matthew |
| Access tokens recreated (docker-push, client-pull, nuxt-studio-proxy-v2, matthew-local-key) | ✅ DONE (15 Aug) — old tokens revoked, new tokens in /root/.config/forgejo-tokens-2026-08-15.txt (0600); docker registry updated+verified; off-host consumers (client VPS client-pull, Nuxt Studio, matthew's machine) need the new values |
OpenCode |
| Private repo secret review + rotation | ✅ DONE (15 Aug) — scan report /root/forensics/secret-scan-2026-08-15.md; all HIGH secrets rotated (wiki.js API token, Keycloak gp/dental/veripath-site/wiki-js, Trilium ETAPI); Stripe confirmed demo; nhs_private_key.pem REAL + in use — NHS-side re-registration needed for rotation (user task); scripts' hardcoded DB password → 0600 config; prevention layer (git filter-repo + gitleaks) pending user coordination |
OpenCode |
| Client host root password rotation + SSH keys (194.164.18.33, 77.68.97.101) | ⏳ OPEN — needs creds | Matthew |
| 77.68.97.101 Postgres bind confirm/fix | ⏳ OPEN — needs creds | Matthew |
| gp.veripath.co.uk + dental.veripath.co.uk restored (502 resolved) | ✅ DONE (15 Aug) — restored on the PRIMARY topology (single home): tun-apps-vps2 stopped+disabled; canonical client DB dsp_clinic_dev migrated VPS2→local client_vps_postgres (verified identical); GP stack up on primary (DB_HOST/CLIENT_DB_HOST overrides); dental.veripath.co.uk → 8011; check-tunnel-health.py timeout crash + 0-byte backup detection fixed; practice backup re-run 49,702 bytes |
OpenCode |
| Keycloak MFA enforced (staff/admin — TOTP authenticator app; matthew enrolled + verified live 15 Aug; recovery codes available). Fingerprint/WebAuthn deferred: not achievable on Ubuntu with current browsers (verified 15 Aug); revisit only with a USB FIDO2 fingerprint key | ✅ DONE (15 Aug) | Hermes |
| Lynis weekly schedule + agent consumption | ✅ DONE (15 Aug) — weekly cron → /var/log/lynis-report.dat; app daily scans + hardening-index trend on dashboard |
Hermes/OpenCode |
| DefectDojo stack up + findings pushed | ✅ DONE (15 Aug) — canonical on backup VPS (77.68.112.126); Trivy/Nmap/ZAP pushes verified landing | OpenCode |
| Forgejo container hardening (read-only, caps, tmpfs, egress) | ✅ DONE (15 Aug) — verified web/git-SSH/webhook after | OpenCode |
| fail2ban on git-over-SSH (2222) | ✅ DONE (15 Aug) — jail forgejo-sshd, live-tested ban |
OpenCode |
| Egress/outbound monitoring + anomaly alerts | ✅ DONE (15 Aug) — egress-monitor.sh + anomaly-alert.sh (every 5/15 min) |
OpenCode |
| Dashboard scan-data freshness (forgejo 16.0.2, no watchtower) | ✅ DONE (15 Aug) | OpenCode |
| Daily check-in rhythm + reminders + enforcement | ✅ DONE (15 Aug) — 08:00 reminder + new 09:15 enforcement cron (/etc/cron.d/security-checkin → /opt/scripts/check-in-enforce.sh): today→OK, yesterday→nudge, ≥2 days→escalation email + journal; weekly reminder Sun/Mon. First scheduled run 09:15 16 Aug |
Hermes/OpenCode |
| Login-gated daily check-in (post-login mandatory screen) | ⏳ OPEN — PLANNED (user-flagged 16 Aug): current enforcement is email-only — after SSO login nothing requires the check-in. Spec in agents/handoff/from-hermes 2026-08-16 |
OpenCode + Matthew |
| Incident runbook rewrite (Standard 6) | ⏳ TODO | Hermes |
| Wiki secrets scrub | 🔄 IN PROGRESS (15 Aug) | Hermes |
| Backup VPS (77.68.112.126) post-incident verification | ✅ DONE (15 Aug) — no artifacts; FIXED broken backup cron (missing user in /etc/crontab) + tmpfs temp-dir ENOSPC; borg archive flowing | OpenCode |
security/security-check-in is read by BOTH/opt/scripts/send-alert-mail.py (config in /root/.config/botnet-mail.conf).security/security-check-in), once per working day, before theagents/handoff/from-hermes 2026-08-16; ownerTraining note: the check-in is deliberately short (5 minutes) and the
same every day, so it becomes habit. The weekly check is the only place
new tool output (Lynis/DefectDojo) is reviewed.
| DSPT standard | Control in this strategy |
|---|---|
| 1–3 Governance | Strategy page, roles, review cadence, incident reports |
| 4–6 Operations | Daily/weekly rhythm, check-in log, runbook, training |
| 7–10 Technical | Patching, container hardening, egress, MFA, monitoring, backups |
Detailed mapping in the DSPT standards pages
(compliance/governance-compliance/dspt-standards/*).
security/revise_strategy_15_08_26).agents/handoff/from-opencode 2026-08-15): gp/dental back up on the PRIMARYclient_vps_postgres; tunnel tun-apps-vps2 decommissioned; practice backupagents/handoff/from-hermes 2026-08-15): DefectDojo confirmed canonical onforgejo-sshd (2222); egress-monitor.sh + anomaly-alert.sh;/root/forensics/secret-scan-2026-08-15.md)