Security

Private by default, and careful with every change

These are the controls the StarlingTek platform actually has. Nothing on this page is a plan for later.

The admin panel

The web admin panel is off by default. When it's on, it's the most exposed part of the platform, so it gets the most checks.

Password and authenticator code
Signing in takes an argon2id-hashed password and a TOTP code from an authenticator app. Each code works once. Repeated failures lock the account and are rate-limited per IP.
A fresh code for every change
Deploying, rolling back, removing a site, changing alert channels or DNS: each needs the site or server name typed out and a fresh authenticator code, both checked on the server.
An audit log
Sign-ins, failures, rejected requests and every change are recorded with the time, target and client IP. Entries hold names, never secret values.
Allowlisted actions
The panel forwards a fixed list of operations to the same handlers stk uses. Any route not on the list answers 404, even with a valid session.
No web terminal
There is no shell in the browser. Server-wide settings, restores and anything not on the list stay an SSH step.
Sessions and CSRF
Server-side sessions, and a CSRF token, same-origin check and JSON body required on every change. The panel never holds the control plane's API token.

The server

Only what has to be public is public.

Three open ports
The firewall allows 22, 80 and 443 and nothing else. fail2ban watches SSH.
Loopback everywhere else
Site containers publish to 127.0.0.1 only. The control plane's API listens on loopback behind a bearer token, and only webhooks and its health route are proxied publicly.
Fail-closed admin
Disabled, the panel answers 403 to everything. Enabled with nobody enrolled, only setup with a one-time token works. It can also be limited to an IP allowlist, or left off the internet and reached over an SSH tunnel.
Automatic HTTPS
Caddy gets and renews Let's Encrypt certificates for every site, with expiry alerts at 21 and 7 days.
Contained sites
Containers run as non-root with dropped capabilities and no-new-privileges. Each site's files live in their own directory.
Least-privilege GitHub access
Private repositories get a read-only deploy key for that one repository, not an account-wide token. Webhooks are verified with an HMAC over the raw body.
Secrets stay secret
Secret environment values are masked in the panel and scrubbed from deploy logs and the audit log. Tokens for DigitalOcean databases are held in memory for minutes and never written to disk.
This website
A strict Content Security Policy with no inline scripts, no third-party assets, no trackers and no analytics.

Found a problem?

If you think you've found a security issue, email [email protected]. Every report is read.