Production security defaults
What production already does, what you still have to set, and what the hardening program will fail closed. The long-term goal is that soli new + soli serve is safe on the public internet without a checklist.
Already on by default (production)
| Control | What it does |
|---|---|
| Auto-escaped templates | <%= %> HTML-escapes, including non-String values |
| CSRF Origin/Referer gate | Cross-site state-changing requests without a matching origin fail |
| Security headers | Standard preset in production (nosniff, frame options, HSTS) |
SSRF on HTTP.* | Loopback and private ranges refused; exceptions are literal host:port in SOLI_HTTP_ALLOW_HOSTS |
| Request body cap | 8 MiB (SOLI_MAX_BODY_SIZE); 413 when exceeded |
| Attachment types | Default allowlist excludes text/html, SVG, XML; blob route sends nosniff + disposition |
| SQL TLS | Postgres/MySQL via rustls; default prefer |
| Panic containment | A panicking handler is a 500; the worker stays up |
| Log redaction | Credential-looking params, binds, locals, and HTTP URLs are redacted |
| Jobs dashboard | 404 in production unless jobs credentials are set |
| Production boot gate | APP_ENV=production (or prod) refuses to start without SOLI_APP_HOSTS (at least one hostname) and SOLI_SESSION_SECRET of 32+ characters. --dev and non-production env skip the gate |
You still set (today)
Not implied by a bare soli serve. Required for a public host:
SOLI_APP_HOSTS— required at production boot. CSRF origin checks use this list, not a forgeableHostheader.SOLI_SESSION_SECRET(32+ chars) — required at production boot; sealed cookies and the cookie session driver derive keys from it.SOLI_CSRF_TOKENS=require— tokens are always verified when present; this makes a missing token a 403 for browser form posts.soli newwrites this into.env. Existing apps stay optional until they set it.permit(...)/attr_accessible—Model.create(params)is not blocked unless you whitelist.sslmode=require(orverify-full) — defaultpreferstill allows cleartext if the server offers none.SOLI_TRUST_PROXY=1— only behind a proxy that strips inboundX-Forwarded-*then sets its own.- Reverse-proxy TLS —
soli serveis HTTP.
Target (hardening program)
Not shipped as defaults yet — do not assume they already fail closed:
- Stricter CSP that matches vendored htmx + Alpine
DATABASE_URLexamples usingsslmode=require
Edge knobs: Server Hardening. Headers: Security Headers. Forms: Forms & CSRF.