Security architecture-first

Even if your database is compromised, your env values stay protected.

ENVCRYPT is designed so your server stores ciphertext, not secrets. Decryption requires your master password, which never leaves your browser.

Browser-side encryption · No standalone app password

Security note: strong protection depends on a strong master password. Weak passwords reduce resistance to offline guessing.

variables table preview
Stored in databaseType

DATABASE_URL

q5q7f...:fNw8Y...

secret

STRIPE_SECRET_KEY

YjRkY...:V2j3n...

secret

OPENAI_API_KEY

c2Fsd...:x81aa...

secret

NEXT_PUBLIC_APP_URL

c2lnb...:a9s2m...

optional

plaintext is never written to value_encrypted

decryption key is not stored in the database

Breach scenario

What happens if your database is leaked?

Attacker gets ciphertext, not secret values

Your database stores encrypted blobs in value_encrypted. Without the decrypt key, those values are unreadable.

Master password is never stored server-side

The key is derived in the browser from your master password and user ID, then kept in memory only.

Breaking one layer is not enough

An attacker would still need to crack your master password against Argon2id before AES-256-GCM decryption becomes possible.

Server can see

  • Project and variable keys (metadata)
  • Encrypted value blob (iv:ciphertext)
  • Timestamps, tags, and variable type

Server cannot see

  • Your master password
  • Derived AES decryption key
  • Plaintext secret values

Implementation details

Security guarantees enforced in code.

AES-256-GCM encryption per value with random 12-byte IV
Argon2id key derivation (iterations: 3, memory: 64 MB, hash: 32 bytes)
API routes reject plaintext payloads (value field)
RLS policies scope rows to auth.uid() ownership
Vault key held in-memory and cleared on lock
Auto-lock defaults to 15 minutes

How it works

End-to-end flow in four steps.

  1. 01

    Sign in with Google or GitHub

    Authentication identifies you. It does not decrypt your secrets.

  2. 02

    Create your master password

    Argon2id runs in your browser and derives your AES key locally.

  3. 03

    Save environment variables

    Each value is encrypted on-device before your app sends it to the API.

  4. 04

    Export when needed

    Decryption happens in-browser, then you download a clean .env file.

secure save path

const key = await deriveKey(masterPassword, userId)
const valueEncrypted = await encryptValue(secretValue, key)

await fetch('/api/variables', {
  method: 'POST',
  body: JSON.stringify({ key: 'DATABASE_URL', valueEncrypted })
})

// API rejects plaintext 'value' fields

Start secure by default

Protect secrets even under worst-case infrastructure events.

Keep plaintext out of storage. Keep decryption keys in the browser. Keep operational security simple.

Start with Google

Google and GitHub OAuth supported.