Current security posture for ablaut.
- Payload auth is used for app users.
- Payload login lockout is enabled:
- 5 failed attempts
- 15 minute lock duration
- Payload auth cookies are HTTP-only.
- Cookie
securebehavior follows the configured public HTTPS URL. - Main app routes require Payload login:
/dashboard/events/channels/users/settings
- Payload admin is super-admin only.
- Non-super-admin access to
/adminand/admin/*redirects before Payload renders a no-access screen. - Public listener/speaker routes do not expose admin data.
- LiveKit tokens are generated server-side only.
LIVEKIT_API_SECRETis never exposed to the browser.- Listener LiveKit token grants can subscribe but cannot publish.
- Speaker LiveKit token grants can publish audio.
- Speaker passwords are hashed.
- Speaker password success uses an HTTP-only session cookie.
- Production
PAYLOAD_SECRETmust be at least 32 characters. - Role-based access is enforced through Payload collection/global access functions and app server actions.
- Config export does not include user password hashes, SMTP secrets, API secrets, or LiveKit secrets.
- Config export/import transfers listener/speaker passwords only as stored hashes.
- Basic security headers are set by
src/middleware.ts:X-Content-Type-Options: nosniffX-Frame-Options: SAMEORIGINReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: camera=(), geolocation=(), microphone=(self)Strict-Transport-Securitywhen the public URL is HTTPS
- Audit logs are written for sensitive changes:
- user created
- user role changed
- user deleted
- event deleted
- channel deleted
- speaker password changed
The app has in-memory per-IP rate limiting for:
POST /api/livekit/listener-tokenPOST /api/livekit/speaker-tokenPOST /api/speaker/verify-passwordPOST /api/users/inviteGET /api/config/export
For multi-instance deployments, replace or extend this with shared Redis/proxy rate limiting.
Current in-process behavior:
- Expired buckets are purged periodically to avoid unbounded memory growth.
- When the bucket map exceeds 10,000 entries, the oldest buckets are evicted.
- Limits are still per app container. Put auth and token endpoints behind reverse-proxy rate limits in production.
Recommended proxy limits remain documented below for Payload-owned auth routes.
Payload owns its auth routes, so production deployments should rate-limit these at the reverse proxy:
POST /api/users/loginPOST /api/users/forgot-passwordPOST /api/users/reset-passwordPOST /api/app/reset-passwordPOST /api/app/login-failure
Recommended starting policy:
POST /api/users/login: 5 requests per minute per IP, burst 10.POST /api/users/forgot-password: 3 requests per 10 minutes per IP, burst 5.POST /api/users/reset-password: 5 requests per 10 minutes per IP, burst 5.POST /api/app/reset-password: 5 requests per 10 minutes per IP, burst 5.- Return
429 Too Many RequestswithRetry-Afterwhen exceeded.
- User visibility is scoped by organization membership for non-super-admins.
- Event assignments require active organization membership unless a super admin overrides in Payload.
- See
docs/ORGANIZATIONS.md.
- Put the app behind HTTPS in production.
- Add CSRF review before adding more cookie-authenticated write endpoints.
- Add backup monitoring and restore drills.
- Review security headers at the reverse proxy.