# Security policy

## Supported baseline

Use a supported PHP 8.1+ release, a current MySQL/MariaDB release, HTTPS, and a dedicated database account. Local root/blank-password examples are development-only and must never be copied to a public host.

## Core protections

Quaeriva's browser mutations require CSRF validation and server-side authorization. Database access uses PDO prepared statements for user-controlled values. Passwords are stored through PHP password hashing, account recovery/verification tokens are stored hashed, and API tokens are stored hashed with scoped authorization; a raw API token is displayed only at creation time.

Rate limits cover account authentication/recovery, question creation, answers, comments, voting, duplicate suggestions, contact messages, and API writes. Public and administration HTML use baseline content/frame/referrer/permissions headers. Administration is explicitly `noindex,nofollow`. HSTS is emitted by public HTML responses when the request is already HTTPS; enabling HTTPS correctly at the hosting/proxy layer remains the deployer's responsibility.

Audit logging records security-sensitive administrative mutations and member API-token create/revoke events. Raw IP addresses are not stored in audit rows; when an address is available it is salted and hashed.

## Secrets and integrations

Keep `config/database.local.php`, `.env`, installation locks, database dumps, backups, API tokens, Telegram bot tokens/chat IDs, session cookies, and mail credentials/details out of source control and public directories.

Telegram and PHP mail are optional integrations. Disabling them must not disable database/in-app operation. Never expose a Telegram bot token in HTML, JavaScript, logs, screenshots, issues, or exported translation files.


## Advertising and user-generated links

Advertising provider code is a privileged administrator-only setting because networks such as AdSense require script/`ins` markup. Community users, moderators without administrator settings permission, questions, answers, comments, API content, and translations do not receive a raw HTML/script execution path. Advertisement configuration rejects PHP tags and oversized code. Image advertisements validate safe root-relative or HTTP/HTTPS URLs, require alternative text, remain responsive, and paid destinations are marked `rel="sponsored"`. The `ads.head_code` setting is an intentional raw-injection boundary available only to administrators, and must be treated as trusted provider code.

User-generated question/answer/comment formatting uses the central safe rich-text formatter rather than raw HTML. Input is escaped before the formatter generates its small semantic allowlist. External user links accept only HTTP/HTTPS and are emitted with `rel="ugc nofollow noopener noreferrer"`; `javascript:`, `data:`, `vbscript:` and protocol-relative URL tricks are rejected.

## Themes and appearance packages

Theme selection, appearance changes, custom CSS, and package import are administrator-only, CSRF-protected settings. Exported JSON packages are designed for offline editing and collaboration, but importing one writes only validated `theme.*` settings and custom CSS; it never extracts PHP templates, JavaScript, or executable assets into `public/themes`. Install additional theme files through the reviewed deployment process. A manifest may support `rtl`, `ltr`, or both; activation is allowed only when it covers every direction required by the currently enabled languages and its `min_core` requirement is satisfied.

## Installer safety

The first-run installer validates database identifiers and administrator fields, uses prepared SQL, hashes the administrator password, and never renders submitted passwords after processing. Database failures are presented generically instead of exposing credentials.

After successful installation, a lock prevents rerunning first-time setup. Prefer storing it outside the public document root. If the hosting layout requires the protected fallback under `install/`, preserve the bundled access restrictions. Do not remove the lock to perform upgrades; use forward migrations instead.

Make configuration writable only as long as necessary during installation, then reduce permissions when the host permits it. Back up the database/configuration before migrations.

## Production checklist

- HTTPS enabled and correctly detected.
- `APP_DEBUG`/error display disabled for public production use.
- Dedicated least-privilege database user.
- Local database configuration outside version control.
- `config/`, storage, backups, and installer lock not publicly downloadable.
- Secure/HttpOnly/SameSite session cookies appropriate for the deployment.
- Administration inaccessible without authentication.
- Mail/Telegram test delivery performed before enabling required workflows.
- GitHub/MySQL CI green for the exact release tag.

## Reporting a vulnerability

Report suspected vulnerabilities privately to the maintainers before public disclosure. Include the affected release, deployment context, minimal reproduction steps without real secrets, expected/actual security behavior, and a suggested mitigation when possible. Do not include real passwords, session cookies, API tokens, Telegram credentials, database dumps, or private user data in an issue or test fixture.
