Isaac Limb ← Portfolio
Project · Self-hosted platform

limbserver

A 47-service self-hosted platform running in production for my family: single sign-on, encrypted secrets, immutable offsite backups, and full observability. Then I attacked it with an AI-driven penetration test and fixed what it found.

Role
Solo, design to production
Stack
Docker · Caddy · Authentik · Cloudflare · restic · SOPS/age
Timeframe
~18 days to production
Status
Live, family use
47containerized services
5composed engines
100%images digest-pinned
30agent pentest fan-out
9.3CVSS found and fixed

What it is

One platform repo orchestrates five service engines through a single make up. Everything shares one identity provider and one secrets store, and nothing is exposed that does not need to be.

Edge Auth Media Apps Portal
Two ingress paths
Direct (streaming, large uploads) → Caddy Cloudflare Tunnel (everything else) → home IP hidden
Bring-up order is load-bearing: edge, then auth, then media, then apps. The portal auto-deploys.

Security was the interesting part

I ran a structured, AI-driven penetration test against my own platform: 30 subagents researched known CVEs for every pinned image, and an external probe tested the live attack surface from outside the network. Findings were tiered L0 to L7.

L7 Kavita pre-auth account takeover (CVSS 9.3) → patched to the hotfix release
L6 Assume-breach reachability: internal databases correctly unreachable
L4 Header-smuggling: forged identity headers stripped at the proxy
L3 MFA-bypass attempts against the public client: failed
L2 Live SSO discovery enumerated and reviewed
The top finding was real and fixable. The rest confirmed the hardening held.

Decisions worth noting

Assume-breach network segmentation, then prove it

Every database and cache sits on a private per-stack network, off the shared bridge. I did not take that on faith: I ran the test from inside a container on the shared network and confirmed the data tiers were unreachable.

# assume-breach test from a container on the shared network
$ nc -z authentik-postgres 5432   # → blocked (name does not resolve)
$ nc -z immich-redis      6379    # → blocked
$ nc -z jellyfin          8096    # → reachable (intended)

A guardrail that stops AI agents from leaking secrets

Because I build and operate this platform with coding agents, I wrote a pre-tool hook that denies any agent attempt to read plaintext secrets, while still allowing the encrypted store. It is real, working defense in depth, and it fired and blocked an agent during this very portfolio's research.

$ agent> read .env
⛔ blocked by .claude/hooks/block-secret-reads.py
   reason: plaintext secret access denied for agents
   allowed: encrypted secrets.sops.env  # decrypt only via `make`

Secrets and recovery designed for the worst day

One encrypted secrets file with two independent recovery keys, immutable offsite backups with a ransomware-proof retention lock, and a disaster-recovery drill that restores and validates every database dump. Built around a box that powers off nightly, so backups catch up on their own.

Outcome

Prodreal family use
1real CVE found and fixed
Offsiteimmutable backups
SSOone login per person

What I'd do differently

I hand-wrote a lot of the operational glue before deciding what deserved to be permanent. Some of it earned its place; some was effort spent on parts that never changed again. Next time I would let the runbook and the pain points tell me what to automate, instead of automating first.

This platform is live, so every hostname, domain, and IP on this page is sanitized. The architecture and results are real; the coordinates are not shown.
← All projects Get in touch →