# Security Policy ## Reporting a vulnerability Please report security issues privately. Do **not** open a public issue. - Use GitHub's [private vulnerability reporting](https://github.com/mosamlife/wpmgr/security/advisories/new), or - Email the maintainers (see repo metadata). We aim to acknowledge within 72 hours and provide a remediation timeline after triage. Coordinated disclosure is appreciated. ## Threat model (summary) - **Multi-tenancy:** the control plane is multi-tenant; one tenant must never read another's data. Enforced via Postgres Row-Level Security plus application-layer `tenant_id` scoping. - **Untrusted agents:** the agent runs on potentially-compromised WordPress sites. All site-supplied data is treated as untrusted and schema-validated. - **Backup storage:** backups are **not** encrypted client-side in shipped builds, so a backup is protected by whatever protects the destination it was sent to. The default destination is a control-plane-managed bucket, so unless a site is pointed elsewhere the control plane holds its chunks; that storage is the operator's own on a self-hosted control plane and WPMgr's on the hosted service. A customer-owned S3-compatible bucket or a local folder on the WordPress host keeps them on storage the operator controls. Uploads to a managed or S3-compatible bucket go over HTTPS; a local destination writes to disk on the site's own server and does no network transfer. Encryption at rest is whatever the chosen destination provides: a bucket can be configured for it, while a local folder gets only whatever the host's own disk does, which WPMgr does not configure and cannot guarantee. Client-side encryption is the intended model and the `age` implementation and per-site key management ship with the agent, but the encrypt step is not enabled. The constraint that the control plane must never hold a backup decryption key stands. ## Cryptography Locked algorithms (changes require an ADR): **Ed25519** (agent request signing), **AES-256-GCM** (at-rest secret encryption), **BLAKE2b-256** (content addressing / integrity; the code identifier and the wire field name both read `blake3`), **age** (backup encryption; implemented, not enabled in shipped builds). The full threat model lives in [docs/security.md](./docs/security.md).