If you discover a security vulnerability, please report it through GitHub Security Advisories. Do not open a public issue for security vulnerabilities.
We will acknowledge reports within 48 hours and provide a timeline for fixes.
| Feature | Implementation |
|---|---|
| Password storage | bcrypt (legacy PBKDF2-SHA256 hashes are verified and auto-rehashed on login) |
| Password policy | Minimum 8 characters with at least 1 uppercase letter and 1 digit (enforced via Pydantic schema validation) |
| Authentication | httpOnly cookie (JWT HS256), Bearer token fallback for API testing |
| Rate limiting | 10/min for registration, 20/min for login (slowapi) |
| CORS | Restricted to localhost, 127.0.0.1, and 192.168.x.x via regex |
| Data isolation | All queries filtered by family_id with membership verification |
| Docker containers | Non-root user (tribu) in both backend and frontend images |
| Docker networking | PostgreSQL and Valkey are not exposed to the host and stay inside the Docker network |
| Build process | Multi-stage frontend build, .dockerignore files for both services |
| CSV import | Row limit (500), range checks on month/day fields, email format validation |
The backend will refuse to start without these variables set:
JWT_SECRET: Used for signing authentication tokens. Generate withopenssl rand -hex 32.DATABASE_URL: PostgreSQL connection string. In Docker Compose, this is constructed fromPOSTGRES_PASSWORD.POSTGRES_PASSWORD: Database password. Generate withopenssl rand -hex 16.
Never use default or placeholder values for these secrets.
- Copy
docker/.env.exampletodocker/.envand generate strong secrets - If exposing Tribu to the internet, put it behind a reverse proxy (nginx, Caddy, Traefik) with TLS
- Keep Docker images up to date for security patches
Follow these steps before exposing Tribu to the internet:
- TLS termination: Place Tribu behind a reverse proxy (Caddy, nginx, or Traefik) with a valid TLS certificate. Caddy handles this automatically with Let's Encrypt.
- Enable secure cookies: Set
SECURE_COOKIES=truein your.envfile. This adds theSecureflag to auth cookies so they are only sent over HTTPS. - Generate strong secrets: Use
openssl rand -hex 32forJWT_SECRETandopenssl rand -hex 16forPOSTGRES_PASSWORD. Never reuse secrets across instances. - Restrict CORS (optional): The default regex allows all
192.168.x.xaddresses. If your instance is public, consider narrowing this to your specific domain by modifying theallow_origin_regexinbackend/app/main.py. - Backups: Schedule regular PostgreSQL backups and test restore procedures. The Self-Hosting Guide documents the built-in backup flow.
- Keep images updated: Rebuild Docker images periodically to pick up security patches in base images and dependencies.
| Limitation | Context |
|---|---|
| No HTTPS in dev | Cookies use secure=false for local development. Set SECURE_COOKIES=true in .env when behind TLS. |
| No CSRF token | SameSite=Lax on cookies provides sufficient protection against cross-origin form submissions. |
| No email verification | Registration does not require email confirmation. |
| No account lockout | Failed login attempts are rate-limited but do not lock accounts. |
Both the backend and frontend Dockerfiles create a dedicated non-root user (tribu) and run all processes under that user. The Docker Compose configuration does not expose database or cache ports to the host, keeping PostgreSQL and Valkey accessible only within the Docker network.
Build artifacts are minimized through:
- Multi-stage builds for the frontend (build step separated from runtime)
.dockerignorefiles excluding development files, git history, and documentation from images