# Security notes and known gaps

## Implemented baseline

- No direct public access to application or secret files when document root is `public/`.
- `password_hash` / `password_verify`, strictly HttpOnly session cookies, SameSite=Lax, cookie Secure when APP_URL HTTPS.
- CSRF validation on admin POST and Fetch JSON mutation routes.
- RBAC: global `owner/manager/viewer`, `admin_bot_access` per-bot ACL for non-owners. The initial CLI owner is allowed across all bots; UI for additional admins remains missing.
- Prepared PDO statements and HTML escaping; CSP prevents inline scripts except static assets from self.
- Tokens encrypted using libsodium secretbox with random nonce and 32-byte APP_KEY.
- 64-hex random Webhook secret in private URL, constant-time comparison, maximum input size 1 MB.
- Idempotent inbound insert, outbound dedupe-key and MySQL advisory lock worker.
- API method allowlist: cannot call arbitrary Bot API or arbitrary external URL through management UI.
- Contact message validation only accepts a contact whose user_id is the sender's identifier when present.

## Production gaps (do not ignore)

- No verified real-source webhook signature/header. Bale documentation in scope shows URL registration and not a secret-token header. A high-entropy secret URL is a practical control, not source attestation. Hide webhook URLs in reverse-proxy access logs.
- Messages and user fields are stored as MySQL text/JSON, not per-field encrypted. Use encrypted disk/DB backup, least-privilege hosting, retention, and legal basis for PII.
- PHP session persistence and brute-force protection should be hardened further (2FA, rotating session IDs, anti-CSRF for advanced flows, central rate limits).
- Worker may lose track of a send if server crashes after remote acceptance and before writing success; exactly-once delivery is not proven. Do not use this version for financial fulfillment.
- No penetration test, no formal load test, no recovery drill, no independent audit, no security scanning of an exposed running service.
- User deletion, retention UI, compliance, sophisticated permissions and bulk opt-in management remain future work.
- The configured APP_KEY must be backed up securely; losing it prevents decrypting tokens and encrypted database backups.

## Secure deployment

Deploy `.env` outside web root, use HTTPS, firewall DB, keep error logs private, and disable server autoindex. Run cron with least-privilege user. Execute database backups on a schedule and transfer encrypted copies offsite. Test restore in a staging DB without replacing production.
