| Version | Security Support |
|---|---|
| 1.x | ✅ Active |
| < 1.0 | ❌ Unsupported |
Do not report security vulnerabilities through public GitHub Issues.
Please use GitHub Security Advisories instead by clicking Report a vulnerability on the repository Security tab.
Include:
- a vulnerability description
- reproduction steps
- potential impact
- a suggested fix, if available
Expect a response within 5 business days.
- local login: bcrypt with 12 rounds, rate limit 20 attempts / 15 minutes
- SSO: trusted headers from a reverse proxy (
x-remote-user) plus a shared proxy-boundary secret (AUTH_SSO_TRUSTED_PROXY_SHARED_SECRET) carried inAUTH_SSO_TRUSTED_PROXY_HEADER(defaultx-sso-proxy-secret) before trusted identity headers are accepted - JWT access token: 60 minutes, HS256
- JWT refresh token: 7 days, hash stored in DB and revocable
- browser sessions use
HttpOnlycookies (sc_access_token,sc_refresh_token) withSameSite=Lax;Secureis enabled automatically in production - login and refresh responses still return token fields for compatibility, but browser session continuity relies on the cookies
- failed login attempts are written to
platform.audit_log
- RBAC:
viewer(read),editor(mutations),admin(administration) - protected endpoints use
requireAuthplus RBAC checks - install endpoints are state-dependent:
/api/v1/install/statusstays public, while pre-READY mutating install routes can be locked behindINSTALL_SETUP_TOKEN
- recommended: Docker Compose secrets mounted as files and passed through
JWT_SECRET_FILE,DB_PASSWORD_FILE, andPOSTGRES_PASSWORD_FILE - alternative: strong environment variables in an isolated
.envfile JWT_SECRETshould contain at least 32 random characters, for exampleopenssl rand -base64 48
- every mutation (CREATE/UPDATE/DELETE) is written to
platform.audit_log - authentication failures are recorded with source IP and user agent
- the audit log is append-only for the application user
- separate
platformanddataschemas - least privilege in production; the app user should not have DDL permissions
- parameterized queries everywhere, no SQL string concatenation
- the application itself listens on HTTP; use TLS termination on a reverse proxy such as nginx or Traefik for production
- trusted-header SSO must be allowed only through a proxy that injects the configured shared-secret header; the backend rejects missing or mismatched secrets before reading identity headers
- if
INSTALL_SETUP_TOKENis not configured, pre-READY bootstrap write routes stay reachable without that extra shared secret; that mode is intended only for isolated or local installs - CORS origins explicitly whitelisted through
CORS_ORIGINS - Helmet.js middleware provides CSP and related browser hardening headers; HSTS should be enforced at the HTTPS reverse-proxy boundary
- PostgreSQL backups are required before upgrades and before destructive reset
flows such as
./deploy.sh rebuild-db - backup cadence should be at least daily for production
- restore rehearsals should be performed regularly, at minimum monthly
- keep at least one recent backup off-host or off-node
- treat
./scripts/restore-postgres.shas the supported recovery path
- security reports: GitHub Security Advisories
- general questions: GitHub Issues with the
securitylabel