-
Notifications
You must be signed in to change notification settings - Fork 2
Security
Lef edited this page Oct 4, 2026
·
3 revisions
How logins, sessions and the public site are protected. The full technical description is docs/SECURITY_MODEL.md. To report a vulnerability, see SECURITY.md.
- Registration is invite only (
backend/invites.json, see Configuration). Invite codes are claimed atomically, and guessing them is rate limited. - Passwords: at least 12 characters, at most 72 bytes, not on a list of ~2,300 common passwords, and not your username or email. Stored with bcrypt (cost 12).
- Wrong username and wrong password get the same answer in the same time, so nobody can find out which accounts exist by logging in.
- Lockouts that back off but always expire (at most 15–60 minutes): per account + address, per account, per address, and per address for wrong invite codes.
- Addresses an account has signed in from in the last 90 days skip the account-wide lock, so someone who knows your username can't keep you locked out.
- Rate limits on login, registration, password changes, AI requests, messages and dice. You get a clear "try again in N seconds" message, not a logout.
- Admins can lift a lock in Admin → Logins & lockouts (by username or one exact IP address), which also has a paged, filterable login audit. The API is
POST /api/admin/auth/unlock.
- Short access token in the browser plus a refresh token in an HttpOnly cookie that only the auth endpoints receive. Each refresh token works once; reusing an old one ends that whole login.
- Log out really logs out (the token is revoked on the server). Sign out everywhere revokes every session.
- Changing your password, being banned or deactivated, or a role change ends all your sessions immediately (a database trigger bumps your token version).
- Every login, failed login and lockout is recorded (
auth_events, readable by admins). - Access tokens last 30 minutes; the browser refreshes them on its own.
- Log lines can't be forged: control characters in anything a client sends (usernames, paths, error messages) are escaped before they reach the logs.
The maintainer's instance at https://srai.srv-box.com goes through a reverse proxy (TLS, HSTS) to the machine running the stack. There's no extra gate in front of it anymore (removed on 2026-10-04): everything is behind the app's own login, invite-only registration, rate limits and lockouts described above. If you run your own public instance, put HTTPS in front of it the same way.
- Only nginx (:80) is reachable from the network; the database, Redis, ChromaDB and the backend listen on localhost.
- The backend runs on gunicorn with debug off and refuses to start in production with weak secrets.
- Errors never include internal details; API responses aren't cached.
- Dice are rolled and posted by the server, so a dice card in the chat is always a real roll.
- Only the AI (with a one-time grant issued alongside a real reply) or an admin can post as the Storyteller.
- OOC-room moderation can't be talked out of a verdict by text inside the message.