Security model
A plain-language explanation of how EnvHQ protects your data today, and what it doesn't do yet. This page is a technical companion to the security sections of the Terms & Conditions.
Encryption at rest — zero-knowledge, end-to-end
Every variable value is encrypted and decrypted client-side — in your browser, or in the envhq CLI on your machine — using XChaCha20-Poly1305. The server only ever stores and transmits ciphertext; it never sees a plaintext value, and never holds a key capable of decrypting one.
The key hierarchy, all derived and held client-side:
- Your passphrase runs through Argon2id to derive a Master Key, which unwraps your personal User Keypair (X25519, generated once at setup).
- Each project has its own randomly generated Data Encryption Key (DEK). The DEK is sealed to the public key of every member with access — anyone who can decrypt one variable in a project can decrypt all of them, but a DEK sealed to you is useless to anyone without your private key.
- A separately generated Recovery Key (shown once, as a printable recovery phrase) wraps your User Keypair a second, independent way — the only other way in if you forget your passphrase. See the Limitations & FAQ page for what happens if you lose both.
This means EnvHQ's operator cannot decrypt your values — not by choice, but because we never hold a usable key. A database leak alone exposes only ciphertext.
Encryption in transit
The web app and CLI both talk to the server exclusively over HTTPS.
Authentication
- Web sessions are handled by Clerk (identity, session cookies, login UI).
- CLI sessions use a browser-based login: the CLI opens a local loopback listener and a PKCE code challenge, you approve the request while signed in to EnvHQ in your browser, and a one-time code is exchanged for a token — the token itself never appears in a URL. Interactive logins are stored in your OS keychain, never as a plaintext file on disk.
- CI/headless use uses a personal access token created from
Settings → CLI Tokens. The plaintext value is shown once, at creation, and only its SHA-256 hash is stored server-side — a database leak alone cannot be used to reconstruct a working token. - Interactive tokens expire after 7 days; the CLI detects expiry and re-runs the browser login automatically. Personal access tokens can be scoped to a single project and to read-only access, and are revocable at any time from the web app.
Authorization / access control
Every project belongs to an organization (every account gets a personal one automatically; you can also create or be invited to team organizations). Every API request is checked against the acting user's resolved role in that project's org — from either the Clerk session or a bearer token. A request for a project you have no access to returns "not found", not "forbidden" — it doesn't reveal whether the resource exists, and a Viewer probing something they can see but can't edit doesn't learn more than a stranger would.
Within an org, access to a specific project is role-based: an org admin/owner automatically has admin access to every project in the org; anyone else needs an explicit grant (to them directly, or to a group they're in) of Viewer, Editor, or Admin. A grant can also be capped per environment — e.g. Editor on dev but Viewer-only on prod— from the same "Manage access" dialog. Org invitations, membership, and roles are managed entirely by Clerk's own hosted UI.
Being authorized for a project and being able to decryptit are separate things: a grant (or org-admin status) controls access through the API, but decrypting a value additionally requires holding a copy of that project's DEK, sealed to your public key. Granting access wraps a copy for the new member right away; if that doesn't land immediately (e.g. they hadn't finished their own key setup yet), any client that already holds the DEK delivers it the next time they open the project — usually within seconds, never more than the next visit.
Version history
Every commit to an environment — a web edit, a CLI push, or a rollback — is stored as a full, immutable, append-only version. You can restore any earlier version at any time, which recovers a deleted or overwritten variable. This does not extend to deleting an entire environment or project, which remains permanent with no recovery path.
What's not covered today
- No key-name / metadata encryption. Only variable values are end-to-end encrypted — project, environment, and variable-key names are visible to the operator.
- No DEK rotation on revoke.Removing someone's access stops them decrypting anything going forward, but doesn't rotate the project's key — they could retain a copy of whatever they already fetched before removal.
- No passphrase-recovery beyond the Recovery Kit. Losing both your passphrase and your recovery phrase means permanently losing access to that data — there is no operator-side reset that preserves it.
- No independent third-party security audit or certification (e.g. SOC 2, ISO 27001).
- No undo for deleting an entire environment or project (individual variable changes are recoverable via version history — see above). See Limitations & FAQ.
- No published rate-limiting or formal abuse-protection policy.
- No formal SLA for uptime or support response time.
Reporting a vulnerability
If you believe you've found a security issue, please report it responsibly to security@envhq.dev rather than testing it against other users' data. We'll do our best to acknowledge and address reports promptly, though — consistent with the rest of this page — we do not currently offer a formal SLA around response time.