# Security

## Encryption

- Values are encrypted with **AES-256-GCM** before they are stored.
- Each project and environment pair has its own **data key**. Data keys are encrypted with a versioned **master key** that is kept outside the database.
- Each ciphertext is bound to its row, so copying ciphertext between rows or environments makes it undecryptable.
- Values are decrypted only to answer an authorized request, and are never written to logs or caches.

envpass decrypts values on the server so that CI, servers and the CLI can read them. If you need a secret that the server can never read, use a share link.

## Share links

Share links let you send one value to someone outside your workspace:

- The value is encrypted **in your browser**. The key is kept in the URL fragment (`#...`), which browsers never send to servers.
- Links expire after 1 hour, 1 day or 7 days and can be opened 1 to 10 times. After the last view the ciphertext is deleted.
- An optional passphrase adds a second secret that is never stored anywhere.

## Access

- Roles grant access per environment, and nobody can grant more access than they have.
- Service tokens are scoped, stored only as a SHA-256 hash, and always expire.
- Removing a member disables their service tokens immediately.
- Personal overrides are visible only to their owner, and never reach service tokens, syncs, webhooks or production.

## Syncs and webhooks

- Vercel and GitHub tokens and webhook signing secrets are encrypted with AES-256-GCM under the master key, bound to their row, and never returned by the API after they are saved.
- A sync reads values with the permissions of the person who set it up, checked on every run. Each run is recorded in the audit log.
- GitHub values are encrypted with the repository's public key before they are sent. New Vercel variables are created as Sensitive, or Encrypted for Development.
- Webhook payloads contain key names, never values. Every delivery is signed with HMAC-SHA256; see [verify signatures](/docs/webhooks#verify-signatures).
- Webhooks only call public `https://` addresses. Private, loopback and link-local addresses are refused, redirects are not followed, and the address is checked again before every delivery.

## Audit log

The audit log is append-only: the database rejects updates and deletes from the application. It records who did what, when and from which IP, but never values.

## Reporting a vulnerability

Email security@envpass.dev. Please do not open a public issue.
