| Version | Supported |
|---|---|
main branch (latest) |
✅ Active development |
| Older tagged releases |
We recommend always running the latest commit on main or the latest tagged release.
If you discover a security vulnerability in OpenFactstore, please do not open a public GitHub issue.
- Go to the Security tab of the repository.
- Click "Report a vulnerability".
- Fill in the advisory form with:
- A clear description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggested mitigations
We will acknowledge receipt within 48 hours and aim to provide a fix or mitigation within 14 days for critical issues.
If you prefer email, send details to the repository maintainers. You can find contact information in the repository profile.
The API has a complete authentication and authorisation model — scoped API keys, per-organisation
sessions, and a role model both resolve into — but SECURITY_ENFORCE_AUTH still defaults to
false, so a default deployment accepts unauthenticated requests.
This is the last step of a deliberate rollout, not an oversight: flipping the default is a breaking change for every existing deployment, so the model ships first and the default flips in a clearly marked release.
For production, turn it on:
security:
enforce-auth: trueBefore you do, run in warn mode to find every unauthenticated caller without breaking them:
security:
warn-mode: trueWarn mode authenticates and authorises as normal but logs what would have been rejected and allows the request through. That is how you discover a forgotten pipeline before it becomes an outage rather than after.
With enforcement on:
- unauthenticated requests get
401withWWW-Authenticate: Bearer; /actuator/**is restricted to health and info — metrics, env and loggers need a credential;- Swagger UI,
/api-docsand the H2 console are no longer served unauthenticated; - HSTS is set and a wildcard CORS origin is refused outright;
- a first-run bootstrap admin credential is created so the deployment is administrable.
A reverse proxy is still good practice for TLS and network isolation, but it is no longer the only thing standing between the internet and your data.
See docs/api-authorisation.md and docs/authentication.md.
When VAULT_ENABLED=false, SCM integration tokens (GitHub, GitLab) are stored Base64-encoded in PostgreSQL. This is encoding, not encryption.
Mitigation: Set VAULT_ENABLED=true and configure HashiCorp Vault for all environments that store real SCM tokens.
Unit tests run against an H2 in-memory database. H2 must never be used in production — use PostgreSQL 16.
Use this checklist before deploying OpenFactstore to a production environment.
- API is not exposed directly to the public internet.
- API is placed behind a TLS-terminating reverse proxy (nginx, Caddy, AWS ALB).
- TLS 1.2+ is enforced; TLS 1.0/1.1 and weak cipher suites are disabled.
- Firewall rules restrict access to port 8080 to known CI/CD IPs and internal networks.
- PostgreSQL (5432) and Vault (8200) are not exposed outside the private network.
-
SECURITY_ENFORCE_AUTH=true— the application refuses unauthenticated requests itself, not only at a proxy. - Warn mode was run first, and its log shows no unauthenticated callers remaining.
-
SSO_JWT_SECRETis set to a real random secret (≥32 bytes). The application refuses to start with a placeholder, but check it is not a value from a shared example. - Unique service accounts and API keys are created per CI pipeline, each scoped with the
CI_PIPELINEpreset rather thanadmin. - Every API key has a TTL;
security.api-key.allow-non-expiringisfalse. - Keys are rotated at least every 90 days, using
POST /api/v1/api-keys/{id}/rotateso the overlap window avoids an outage. - Keys are bound to an organisation (
orgSlug) where the deployment is multi-tenant. - The bootstrap credential has been used, revoked, and
security.bootstrap.enabledset tofalse. -
security.cors.allowed-originslists the real origins; it is not*. - Default Grafana password (
changeme) has been changed.
-
DB_PASSWORDis stored in a secrets manager (AWS Secrets Manager, GCP Secret Manager, Vault). -
VAULT_TOKENis stored in a secrets manager; consider Vault auto-unseal via KMS. - SCM tokens are stored in Vault (
VAULT_ENABLED=true), not plain PostgreSQL. - No secrets are committed to source control.
- PostgreSQL is running with encryption-at-rest enabled.
- Regular automated backups are configured and tested.
- Database user
factstorehas minimum required privileges (no superuser). - Flyway migrations are the only mechanism for schema changes.
- Prometheus and Grafana are not exposed to the public internet.
- Grafana is secured with SSO or strong admin credentials.
- Alerting is configured for
factstore_assert_noncompliant_totalspikes. - Audit log (
GET /api/v1/audit) is monitored for anomalous access patterns.
- A process exists to track and apply dependency updates (Dependabot or Renovate).
- Container images are rebuilt regularly to pick up OS patch updates.
- The Dockerfile base image (
eclipse-temurin:21-jre-alpine) is pinned by digest in production.