CMS Security: CSRF, Rate Limiting, Encryption
AliothPress applies layered security to every installation: CSRF tokens on all state-changing requests, rate limiting with automatic brute-force lockout, optional two-factor authentication with layered recovery, encrypted storage for SMTP passwords and API keys, allow-list HTML sanitization, server-side SVG cleaning, strict security headers on every response, and a persistent audit log of admin activity. Sessions are invalidated the moment a password changes. All of this is active by default and requires no configuration.
CSRF tokens and rate limiting
Every POST, PUT, and DELETE request in the admin panel carries a CSRF token, verified server-side. A failed check returns a clear message with a retry path.
Rate limiting runs on top. The login endpoint accepts 10 attempts per minute, public form submissions and API endpoints have their own per-minute budgets, and expensive operations such as update checks are capped per hour. Exceeded limits return a friendly error page.
Brute-force lockout
Failed logins are tracked per IP address and username. Five failed attempts for the same IP and username pair, or twenty failed attempts from one IP across any accounts, within 15 minutes block further attempts from that IP for 15 minutes. The pair-based counter keeps the lockout precise: one colleague mistyping their own password does not lock the whole office out, while an attacker cycling through many accounts from one address hits the per-IP ceiling. Every failed attempt, successful login, and block event lands in the audit log with the IP recorded. Old attempt records are cleaned up automatically.
Optional two-factor authentication
Accounts can add a second sign-in step with time-based one-time codes (TOTP). Any authenticator app works: the implementation follows RFC 6238 and uses only the Python standard library, so no external service is involved. The feature is off by default. The owner enables it site-wide in Settings, and each user then opts in from their profile by scanning a QR code and confirming a live code. The secret is stored encrypted, the same way as SMTP passwords and API keys, and a "trust this browser" option skips the second step on that device for 30 days. Disabling or resetting 2FA invalidates every trusted browser at once.
Recovery is layered, so a lost phone does not mean a lost account. Setup generates ten one-time recovery codes, stored as hashes and burned on first use. A one-time sign-in code can be sent to the account email. An Owner or Admin can reset 2FA for another user from the Users page, though an Admin cannot strip the Owner's second factor. And a solo owner locked out of everything can create an empty file named DISABLE_2FA next to the application to skip the second step, flagged loudly in the interface and in the audit log until the file is removed. Enrollment, failed second-step attempts, resets, and bypasses all land in the audit log.
Secrets are encrypted at rest
SMTP passwords, AI provider API keys, and license keys are encrypted with Fernet symmetric encryption before they reach the database. The encryption key derives from the application secret, which lives in the .env file on the server. A database dump alone does not expose credentials.
Content sanitization
HTML from the editor passes through an allow-list sanitizer: permitted tags and attributes survive, everything else is stripped, script injection included. Uploaded SVG files are cleaned the same way, losing script tags, event handlers, javascript: URLs, and external references before storage. Image uploads are restricted to an explicit extension list and re-encoded during processing.
Security headers on every response
Each response carries X-Frame-Options: SAMEORIGIN against clickjacking, X-Content-Type-Options: nosniff, X-XSS-Protection, a strict-origin-when-cross-origin referrer policy, and a Permissions-Policy that disables camera, microphone, and geolocation. Over HTTPS, HSTS with a one-year lifetime and subdomain coverage is added.
Password change ends every session
Each user record carries a session version. Changing the password increments it, and every existing session for that account stops working immediately. A stolen cookie dies with the old password.
Audit log
Significant admin actions are recorded: logins, failed logins, blocked IPs, content changes, backup creation, user management. Each entry stores the user, action, IP address, and a detail message that displays in the admin language of whoever is reading the log. Old entries are pruned on a schedule, so the log stays useful without growing forever.
Role-based access
Settings, user management, email configuration, and maintenance tools are restricted to the Owner and Admin roles. Editors work with content only. Plugin installation and plugin restore from backup are gated to the Owner, since plugin files are executable code. The full role model is covered in the Users and Roles article.
Key security features in AliothPress
CSRF protection on all forms, per-endpoint rate limits, automatic 15-minute lockout after five failed logins per IP and username pair (or twenty per IP), optional TOTP two-factor authentication with recovery codes and an email fallback, Fernet-encrypted credentials, allow-list HTML and SVG sanitization, strict security headers with HSTS, instant session invalidation on password change, and a translatable audit log. Every layer is enabled from the first request after installation.