Security
AltWarden is built on one assumption: the database will leak someday. Everything below follows from planning for that.
What a stolen database gives an attacker
| They would get | They would not get |
|---|---|
| Discord IDs, usernames and avatars of people who tried to verify | Any IP address, email address, cookie value or fingerprint |
| Attempt results and labels | Any Discord access or refresh token |
| Appeal text, staff notes on appeals, and staff names in the audit log | Any API key, because only its hash is stored |
| Keyed hashes they can't read without the key | A way to connect one person's hashes across two servers |
| Webhook addresses and secrets, and any proxycheck.io key, encrypted | Any of those in readable form, without the master key |
| For staff signed in during the last 12 hours, the names of the servers they share with AltWarden | The rest of their server list |
How it's built
- Identifiers are hashed with HMAC-SHA256 under keys derived per server and per kind with HKDF from RFC 5869.
- A server's webhook addresses, webhook secrets and proxycheck.io key have to be read back to be used, so they're encrypted with AES-GCM under a key derived for that server. A stolen database alone reveals none of them.
- The master key lives in the process environment and never in the database or its backups.
- Discord tokens stay in memory for one read, are never stored, and are revoked under RFC 7009 right after. Staff who save Discord's command permissions approve one write, and that token is revoked the same way.
- Verification links are stored as hashes, work for one member, and expire.
- The sign-in state value is tied to the browser that started it, and the check only runs in the browser that signed in, so a link sent to someone else is useless.
- Every page sends a strict Content Security Policy that allows scripts from this site only.
- Verification requests from another site are refused.
- The page that receives Discord's code loads nothing and redirects at once, as RFC 9700 section 4.2.4 advises.
- Browser libraries are copied into this site at fixed versions, so a compromised CDN can't reach members.
- No admin tools listen on public addresses. The application binds to the local machine behind a proxy.
- Request logs are off in the application, its error log names the route and not the address, and the site's access log records no client addresses or page paths.
- The application reads a member's address from the last value the proxy added, because a client can send forged lines ahead of it. If the proxy stops sending one, verification answers with an error, so members never share one stored address.
- A server can only choose channels in that server, and a post is refused if a channel turns out to be somewhere else.
- Only the owner of the Discord app can add the bot to a server, because Public Bot is off. The add link asks for Administrator by default.
Reporting a message
Server staff can rewrite the messages AltWarden posts, so each rewritten message names the person who wrote it. If one is a scam or harassment, tell that server's owner, report the message to Discord, and open an issue on GitHub with the server's name.
Reporting a problem
Report security problems privately through GitHub, not in a public issue.