# Plan: Security Hardening & Documentation Prompted by user feedback — reluctance to run a public-facing server with write access without understanding the threat model. ## Problem There's no security documentation. Security-conscious users have to guess at the attack surface and hardening options. This blocks public adoption. ## Security Page for the Website Document the actual security model so people can evaluate it: ### Attack Surface - No code execution, no shell, no database, no sessions, no templates - Server accepts markdown text and writes it to a single directory - 6 verbs: FETCH, LIST, VERSIONS (read), PUBLISH, APPEND, ARCHIVE (write) - Writes require a valid SHA-256 capability token - Every write is versioned — full audit trail - Rate limiting and size limits (1 MiB body, 64KB frontmatter) already enforced - QUIC/TLS encrypted transport - Logs go to stderr (captured by systemd journal) — server writes nothing outside the content directory ### What a compromised write token gets you - Ability to publish/overwrite/archive markdown files in the content root - Nothing else — no code execution, no filesystem escape, no privilege escalation - Tokens are revocable, writes are audited with token labels ### What a compromised server process gets you - Read/write access to the content directory (with systemd hardening: nothing else) - No access to /home, /etc, or anything outside the content root - No ability to escalate privileges ## Systemd Hardening Add to install script (`setup_systemd`) and deployment docs: ```ini ProtectSystem=strict ReadWritePaths=/srv/site PrivateTmp=yes NoNewPrivileges=yes ProtectHome=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectControlGroups=yes RestrictNamespaces=yes RestrictSUIDSGID=yes ``` ## Write Isolation (optional, for maximum lockdown) For users who want Gemini-level read-only public exposure: - Bind server to `127.0.0.1` for write operations (CI/local clients publish to localhost) - Public traffic reaches the server via iptables redirect or a second read-only listener - Versioning still works because publishes go through the protocol locally - This is the same trust boundary as Gemini — local writes, public reads ## Comparison to Other Servers | | SSH | Web + CGI | Gemini | Demarkus | |---|---|---|---|---| | Code execution | Yes (shell) | Yes (scripts) | No | No | | Database access | Yes | Often | No | No | | Write access | Full machine | Varies | None (read-only) | Content dir only | | Auth model | Keys/passwords | Sessions/cookies | Client certs | Capability tokens | | Worst case | Full compromise | RCE, data breach | DoS | Markdown overwrite | ## Implementation Order 1. Security page on the website (no code changes) — DONE 2. Systemd hardening in install script + deployment docs (no code changes) — DONE 3. Install script detects insecure existing config on update, prompts to harden with rollback — DONE 4. `-read-only` flag or bind-address write isolation (small code change, can defer) ## Status Items 1-3 implemented on main branch. Pending review.