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.

Frequently Asked Questions

Does AliothPress protect against brute-force login attacks?
Yes. Five failed attempts for one IP and username pair, or twenty from one IP in total, within 15 minutes trigger a 15-minute block, on top of a 10-per-minute rate limit on the login endpoint. All events are audit-logged with the IP.
Are SMTP passwords and API keys stored in plain text?
No. They are encrypted with Fernet before storage, using a key derived from the server-side application secret. The database alone does not reveal them.
What happens to active sessions when a password changes?
They are invalidated immediately. Each session carries a version number that stops matching after the change, forcing re-login everywhere.
Does AliothPress sanitize uploaded SVG files?
Yes. Scripts, event handlers, javascript: URLs, and external references are removed on the server before the file is saved.
Is there a log of admin activity?
Yes. The audit log records logins, failures, blocks, content changes, backups, and user management, each with user, action, and IP, displayed in the admin language of the viewer.
Does AliothPress support two-factor authentication?
Yes, as an option. The owner enables it site-wide, then each user activates it in their profile with any authenticator app. Recovery covers one-time codes, sign-in codes by email, admin reset from the Users page, and a break-glass file for a locked-out solo owner.