# Security Policy ## Supported versions Only the latest release receives fixes. The project is deployed from `main` via GHCR images, so the newest tag is what is expected to be running. | Version | Supported | | -------------- | --------- | | latest release | yes | | anything older | no | ## Reporting a vulnerability **While this repository is private**, open an issue here: only collaborators can see it, so the report stays private by construction. **Once this repository is public**, use GitHub's private vulnerability reporting instead — Security → "Report a vulnerability" — and do not open a public issue. That route has to be switched on first (Settings → Security → Private vulnerability reporting); it is unavailable on private repositories, which is why it is not the primary channel here yet. Either way, please do not include working exploit code in the first report — a description of the affected route or component, the preconditions, and the impact is enough to start. What helps most: - the affected component (backend route, player, admin SPA, deployment) - what an attacker needs beforehand: no account, any account, an org role, a screen API key - the effect: cross-tenant read or write, privilege escalation, code execution, denial of service - the version or commit you tested You can expect an acknowledgement within a week. Fixes for anything that lets a tenant reach another tenant's data are prioritised above everything else. ## Scope In scope: the backend API, the admin SPA, the player, the LG webOS shell, the container images and the Ansible deployment in this repository. Out of scope: findings against a third-party service the platform integrates with (report those to that vendor), and reports produced by a scanner without a description of the actual impact here. ## Notes for operators Several defaults matter for the security of a deployment and are not enforced by the software: - `JWT_ACCESS_SECRET` must be a strong random value of at least 32 characters. - `vault_mynextscreen_postgres_password` has no default — the deployment fails without it, on purpose. - `SECRETS_ENCRYPTION_KEY` is mandatory: every stored secret — including the users' TOTP secrets — is encrypted with it and the database rejects plaintext. Keep a backup of the key apart from database dumps; losing it means every user with MFA has to be reset. - Super-admins always use a second factor (TOTP). Consider requiring it for organisations as well (organisation settings); it then applies to every member in all of their organisations. - A super-admin who has lost both the authenticator and the recovery codes, with no second super-admin to reset them, can only be recovered from the database — see _Emergency: the only super-admin is locked out_ in [docs/configuration.md](docs/configuration.md#emergency-the-only-super-admin-is-locked-out). That path writes no audit entry; keeping two super-admins avoids it. - `SIGNUP_ENABLED=false` closes self-registration if the instance is not meant to be open. - Reaching the backend only through the reverse proxy is what applies TLS, the security headers, rate limiting and fail2ban; the published container ports bind to loopback for that reason.