envHQ

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.

EnvHQ is a free tool under active development. Read this whole page before storing anything you cannot afford to lose or have exposed — also see Terms & Conditions and Limitations & FAQ.

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.