Skip to content

Security: rlnunez/OpenOptOut

SECURITY.md

Security policy

OpenOptOut stores sensitive patron data including names, addresses, phone numbers, and email accounts. Security reports are welcome.

Reporting a vulnerability

Please do not open a public issue for a security problem.

Report privately via Report a vulnerability (Security tab → Report a vulnerability).

Include:

  • Vulnerability description and security impact
  • Reproduction steps (request, script, or screenshot)
  • Affected version or commit (from /api/health)

You should receive a reply within 7 days. Fixes will credit reporters in the security advisory unless anonymity is requested.

Scope

In scope: backend API, web UI, plugin sandbox (bubblewrap, seccomp, gRPC broker), encryption at rest, authentication (local, OIDC, SAML, LDAP, SIP2), distributed workers, installers, and Docker images.

Out of scope: data broker websites, and vulnerabilities requiring an already compromised host/admin account (unless enabling sandbox escapes or cross-tenant privilege escalation).

Memory Hygiene & Host Hardening

OpenOptOut implements defense-in-depth against data leakage from process memory:

  • Core Dump Suppression: Core dumps disabled at process level (RLIMIT_CORE = 0), container level (ulimits: core: 0), and systemd service level (LimitCORE=0) so patron PII is never written to disk on crash.
  • In-Memory Zeroization: Decrypted secrets and patron records wrap in ephemeral scoped buffers (core.memory_hygiene.SecureBuffer) and zeroize immediately upon block completion.
  • Encrypted Swap: Operators should run in pure RAM or configure ephemeral encrypted swap via /etc/crypttab (/dev/urandom key) to prevent cleartext memory paging.

Architecture & Cryptographic Controls

OpenOptOut enforces rigorous defense-in-depth protections across all layers:

  • Credential & Secret Isolation: Database and proxy credentials, TLS certificates, and encryption keys are read exclusively from environment variables or mounted files (Docker/Kubernetes secrets, HashiCorp Vault). Secrets are never stored in plaintext database tables and are never written to logs.
  • PII Field Encryption: Identifiers (names, physical addresses, phone numbers, email accounts) can be Fernet-encrypted prior to database persistence via FIELD_ENCRYPTION_KEY.
  • Key Separation & Cryptographic Derivation: Operators and installer scripts can configure distinct random keys for SECRET_KEY, SEARXNG_SECRET, DB_ENCRYPTION_KEY, and FIELD_ENCRYPTION_KEY. Where dedicated subsystem keys are not explicitly supplied, OpenOptOut uses RFC 5869 HKDF (backend/core/hkdf.py) to derive cryptographically isolated, purpose-specific keys for settings encryption, OAuth credentials, MFA tickets, envelope HMAC signatures, and queue payload encryption. Auto-generated keys use non-deterministic lengths (128..256 hex characters / 64..128 raw bytes) to prevent brute-force heuristics and key-length guessing attacks.
  • User-Driven Master Key Generation: The main SECRET_KEY is generated by the administrator via the web interface — combining cryptographic image entropy with physical human randomness (mouse movement and keyboard typing), pure mouse/keyboard entropy, or entering a custom 128+ character key.
  • Filesystem Permission Lockdown: All key-bearing files (secret.key, .env, and dedicated key files) require strict owner-only file permissions (0600 on POSIX, owner-only ACLs via icacls on Windows). The system actively monitors and alerts if permissions are broader than owner-only.
  • Server-Side Authorization: Every administrative, family management, and patron data API route enforces authentication and role boundaries. Unauthenticated endpoints are strictly limited to container health probes (/api/health), sign-in session initialization (/api/auth/*), and public translation catalogs (/api/i18n/translations/*).
  • Bot-Evasion Realism: User-agent rotation and residential proxies defend against basic IP rate limits, but do not claim to defeat advanced behavioral browser fingerprinting.
  • Mandatory Production HTTPS: Deployments must run behind TLS (Caddy, Traefik, or reverse proxies) to prevent plaintext transmission of session tokens, passwords, and patron data. See docs/admin/https.md.

Automated scanning

Every change is verified by automated scanners. See docs/dev/security-scanning.md.

There aren't any published security advisories