Security
Authentication
TREK supports three authentication methods:
Local Password Auth
- Passwords hashed with bcrypt (12 rounds, salted)
- JWT tokens (HS256, 24-hour expiry) stored in
trek_sessionhttpOnly cookie - Rate limiting: 10 login attempts per 15 minutes per IP
OIDC / Single Sign-On
- See Single Sign-On for full setup
- Group-based admin role mapping via claims
- First OIDC login can auto-promote to admin when
OIDC_ONLY=true
Two-Factor Authentication (MFA)
- TOTP-based (works with Google Authenticator, Authy, etc.)
- QR code setup with 10 encrypted backup codes
- Admins can enforce MFA for all users via Admin Panel → Security → Require MFA
- Users without MFA are blocked from all actions until they set it up
Encryption at Rest
Sensitive data is encrypted with AES-256-GCM before storage:
| Data | Encrypted |
|---|---|
| Google Maps API key | Yes |
| Unsplash API key | Yes |
| OpenWeather API key | Yes |
| Immich API key | Yes |
| MFA TOTP secrets | Yes |
| MFA backup codes | Yes |
| OIDC client secret | Yes |
| SMTP password | Yes |
Encrypted values are stored with an enc:v1: prefix. The encryption key is configured via the ENCRYPTION_KEY environment variable or auto-generated in data/.encryption_key.
To rotate the encryption key:
docker exec -it trek node --import tsx scripts/migrate-encryption.ts
Rate Limiting
| Endpoint | Limit |
|---|---|
| Login | 10 attempts / 15 min per IP |
| MFA verification | 5 attempts / 15 min per IP |
| Password change | 5 attempts / 15 min |
| Backup creation | 3 per 60 min |
| MCP API | 60 requests / min per user |
| WebSocket messages | 30 per 10 sec per connection |
CSRF Protection
TREK uses SameSite: Lax cookies for session management. This prevents cross-site request forgery without requiring explicit CSRF tokens, as the browser only sends the cookie with same-site requests and top-level navigations.
CORS
- Development: All origins allowed
- Production (no ALLOWED_ORIGINS): Same-origin only (CORS disabled)
- Production (with ALLOWED_ORIGINS): Only whitelisted origins allowed
SSRF Protection
Outbound requests (e.g. to Immich, webhook URLs) are validated:
- Private IPs (RFC-1918: 10.x, 172.16-31.x, 192.168.x) blocked by default
- Loopback (127.x) and link-local (169.254.x) always blocked
- Set
ALLOW_INTERNAL_NETWORK=trueto allow LAN access (e.g. for Immich on the same network)
Container Security
The Docker image is hardened:
- Runs as non-root user via
su-exec - Read-only root filesystem
- Drops all Linux capabilities except CHOWN, SETUID, SETGID
/tmpmounted withnoexec,nosuid(64 MB)dumb-initfor proper signal handling- Health check on
/api/health
Audit Logging
All security-relevant actions are logged to the audit_log table and viewable in Admin Panel → Audit:
- User registration, login, password change, account deletion
- Trip create/update/delete
- Admin actions (user management, permission changes, OIDC config)
- Backup create/restore/delete
- Each entry includes: timestamp, user ID, action, resource, IP address, details
Content Security Policy
TREK sets CSP headers via Helmet:
script-src 'self'img-src 'self' https:(plus known tile providers)connect-src 'self' https:(plus maps/weather APIs)
Reporting Vulnerabilities
Email mauriceboe@icloud.com with details. Response within 48 hours.