Auditing a Stackpit deployment
Produce a ranked findings list, not a lecture. Check the live stackpit.toml against the rules Stackpit already enforces at startup and the operator guide, rank by severity, and let the user choose what to fix. Read the config that is actually deployed; do not assume the example or init-generated file.
1. Locate the config and the deployment shape
Find the active stackpit.toml (-c/--config), the storage backend (SQLite vs Postgres), the bind addresses, whether auth is enabled, and whether it sits behind a TLS proxy. Stackpit enforces most of these rules at startup; rationale is in docs/operator-guide.md.
2. Try booting under the real rules
Stackpit fails closed on many misconfigurations at startup, so a stackpit serve (or a config parse) against the live file surfaces the enforced findings directly. Fold any startup error or warning into the punch-list.
3. Walk the checklist
For each item, record pass/fail and severity. Highest-severity items first:
- No-auth posture (critical). Stackpit refuses to start with no
admin_tokenand no OAuth unless bound to loopback andno_auth_loopback_acknowledged = true. Flag anyno_auth_loopback_acknowledged = true, or a non-loopback bind with no auth. - Admin token strength.
[server].admin_tokenpresent, ≥16 chars, not a placeholder or weak string. Recommendopenssl rand -hex 32. Confirm the admin token, anyclient_secret, and SMTP credentials are production values, not ones carried over from an example config. - Secure cookies over HTTP. With auth on and a non-loopback bind,
[server].force_secure_cookiesmust betrue(startup fails otherwise) andexternal_urlmust behttps://behind the TLS proxy. - Master key and secret separation.
STACKPIT_MASTER_KEY(or[server].master_key) set, especially with OAuth (required). Confirm the key is not stored in the same directory or backup as the DB; env var override lets it live in a secrets manager / systemdEnvironmentFile. Without the key and without OAuth, integration secrets sit in plaintext in the DB. - OIDC confused-deputy hardening.
web_audiencepresent (mandatory when OAuth enabled); cross-originpost_logout_redirect_urionly with explicit opt-in; redirect URIs absolute http(s);refresh_token_max_ttl_secswithin the 90-day cap; introspection cache TTL ≤ 300s; JWKS TTL ≥ 60s. Confirm audience/scope binding and anyemail_verifiedreliance. - Trusted proxies.
[server].trusted_proxiesset to the actual proxy IP/CIDR (loopback always trusted). Misconfiguration lets clients spoofX-Forwarded-For/X-Real-IPand bypass the rate limiter. - Admin-port exposure. The admin listener (web UI + JSON API) firewalled or proxy-restricted, especially when
bindis widened to0.0.0.0for a container. The ingest listener (:3001) is intended to be public; the admin one is not. - SMTP over plaintext.
[email]userset withtls = "none"is refused at startup;tls = "none"only for a loopback sink. - Filter mode.
openauto-provisions projects/keys on first ingest; for an exposed instance recommendclosedplusrate_limitandmax_projects/max_native_orgs_per_userbounds. - Body-size limits.
max_body_sizeandmax_compressed_body_sizeleft at sane values (decompression-bomb guard). - Retention.
[storage].retention_days = 0keeps data forever (startup warns); confirm it is intentional. - Commercial metrics. If
/metricsis used, it is license-gated and needsSTACKPIT_METRICS_TOKEN; keep the admin port network-restricted even though the token is the real gate (fails closed: 404 without license/token, 401 on mismatch).
4. Report
Present a numbered, severity-ranked punch-list (critical first), one line per finding with the offending file/key and the fix, in the style of the rust:review / security:review skills. Then offer to apply the fixes the user selects. Do not change config as part of the audit itself unless asked.