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:
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.1for 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
- Security page on the website (no code changes) — DONE
- Systemd hardening in install script + deployment docs (no code changes) — DONE
- Install script detects insecure existing config on update, prompts to harden with rollback — DONE
-read-onlyflag or bind-address write isolation (small code change, can defer)
Status
Items 1-3 implemented on main branch. Pending review.