Skip to content

Security baseline

Last verified:

View Markdown

This is the floor, not the ceiling. Use the current OWASP Top 10 as the risk list and the OWASP ASVS as the detailed checklist; choose ASVS level 1 for simple sites, level 2 for anything with accounts, payments or personal data.

  • Any feature touching accounts, payments, personal data, file uploads, admin functions or LLM tools MUST have a short threat model in the spec: what is valuable, who might attack it, how, and what stops them.
  • Prefer a proven provider or framework auth over custom code. Never write your own password hashing or session crypto.
  • Passwords hashed with a modern slow algorithm (Argon2id, scrypt or bcrypt) through the framework.
  • Support multi-factor authentication for admin accounts at minimum.
  • Session cookies: Secure, HttpOnly, SameSite=Lax or Strict; rotate the session on login and privilege change; expire idle sessions.
  • Login, sign-up and password reset are rate-limited and do not reveal whether an account exists.
  • Deny by default. Every endpoint and page declares who may access it.
  • Check permission per object on the server (does this user own this order?), not only per route.
  • Never trust IDs, roles or prices sent from the client.
  • Validate every input on the server against a schema (type, length, format, allowed values).
  • Use parameterised queries or the ORM; never build SQL or shell commands by string concatenation.
  • Encode output for its context (HTML, attribute, URL, JS). Use the framework’s auto-escaping; treat any “raw HTML” escape hatch as a security review item.
  • Sanitise user-supplied rich text with an allowlist sanitiser.
  • Server-side requests to user-supplied URLs MUST use an allowlist and block internal addresses (SSRF).
  • HTTPS everywhere; HSTS enabled.
  • A Content Security Policy that avoids 'unsafe-inline' and 'unsafe-eval' for scripts (use hashes or nonces).
  • X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, a restrictive Permissions-Policy, and frame-ancestors 'none' (or a defined allowlist).
  • CORS allows only named origins; never * with credentials.
  • CSRF protection on every state-changing form or cookie-authenticated request.
  • Secrets live in the platform’s secret store or environment variables, never in the repo, client bundle, logs, prompts or screenshots.
  • .env files are git-ignored; .env.example holds names only.
  • Rotate any secret that was exposed, even briefly, and record it.
  • Use separate credentials per environment with least privilege.
  • Validate uploads by content type and size, store them outside the web root or in object storage, rename them, and serve with safe headers. Scan where risk justifies it.
  • Rate-limit authentication, forms, search, expensive endpoints and LLM calls.
  • Bot protection on public forms where spam is likely.
  • Threat model for sensitive features
  • Framework auth, MFA for admins, secure cookies
  • Deny-by-default, per-object authorisation
  • Schema validation; parameterised queries; context encoding
  • CSP without unsafe-inline scripts; security headers set
  • No secrets in repo, bundle, logs or prompts
  • Rate limits on auth and expensive endpoints