Back to home
§ Security

How we keep your secrets, secret.

Effective May 31, 2026 · v0.1
TL;DR
AES-256-GCM, key derived from your master password through PBKDF2 (210,000 iterations). Keys sit in the macOS Keychain behind Touch ID. We never see plaintext.
§ 01· The short version

In one paragraph.

justenv is a local-first, end-to-end-encrypted secrets vault. Your master password never leaves your Mac, the data encryption key never touches our servers, and your secrets are AEAD-encrypted with a modern authenticated cipher before any byte is written to disk. If we got hacked tomorrow, the worst an attacker would find is encrypted blobs and minimal metadata.

§ 02· What we protect against

Threat model.

We do protect against:

  • A lost or stolen Mac (vault is at-rest encrypted; no key on disk).
  • A breach of our servers (we only hold ciphertext + minimal metadata).
  • Network eavesdroppers (TLS in transit; key material never transits).
  • Someone shoulder-surfing your Mac (Touch ID gate on destructive ops, auto-lock on sleep/screen-lock).

We cannot protect against:

  • Malware running on your Mac with kernel access or a keylogger active while you type your master password.
  • You sharing your master password with someone else.
  • You disabling auto-lock and walking away from an unlocked Mac.
  • Coercion (rubber-hose cryptanalysis is, regrettably, still a thing).
§ 03· The cryptographic chain

How encryption works.

When you create a vault, you pick a master password. The app uses it to derive a Key Encryption Key (KEK), which then unwraps a per-vault random Data Encryption Key (DEK). The DEK encrypts your vault JSON with AES-256-GCM. None of these steps require a network call.

Mac app KDFPBKDF2-HMAC-SHA256 · 210,000 iters · 16-byte salt
CLI KDFScrypt · N=16384 r=8 p=1 · 16-byte salt
CipherAES-256-GCM (authenticated)
DEK length32 bytes (CSPRNG)
Vault format{ kdf, wrappedKey, vault } · base64-SealedBox
Mac vault path~/Library/Application Support/JustEnv/vault.json
CLI vault path~/.envsvault/vault.enc

The implementation is in Sources/Core/Security/Crypto.swift for the Mac app and src/core/crypto.ts for the CLI.

§ 04· Where the keys live

The Keychain, not our servers.

The data encryption key is stored in the macOS system Keychain with kSecAccessControlUserPresence — meaning it can only be read when the user is physically present (Touch ID or system password). The key never leaves your Mac, never reaches our servers, and is never written to plain disk outside the Keychain.

Keychain servicedev.elfora.JustEnv
Keychain accountvault-dek
Access control.userPresence (Touch ID or system password)
§ 05· Locks that close themselves

Touch ID & auto-lock.

Destructive operations (deleting a project, deleting a variable) are gated on Touch ID. The DEK is read from the Keychain only on successful presence check.

The vault auto-locks when the system sleeps, when the screen locks, or after a user-configurable idle timeout. We subscribe to NSWorkspace.willSleepNotification, screensDidSleepNotification, and the distributed com.apple.screenIsLocked notification. Both auto-lock triggers are toggleable in settings.

§ 06· Sharing without trusting the server

Self-destructing share links.Roadmap

At launch, justenv ships a share-link service that lets you send a secret (or a small bundle) to a teammate without ever exposing plaintext to our servers. The protocol:

  • Sender picks the secrets, the TTL, and (optionally) the maximum number of views.
  • The app generates a random 256-bit AES key locally, encrypts the payload, and uploads only the ciphertext + envelope.
  • The app produces a URL where the key lives in the URL fragment (the part after #) — fragments are never sent to servers.
  • The recipient opens the link. Their browser pulls the ciphertext, derives the key from the fragment, and decrypts in-page.
  • The server marks the link consumed (single-view) or schedules deletion at TTL expiry. Defaults: 24h TTL, single view.

Our server sees: an opaque ciphertext blob, an envelope (algorithm identifier, IV, tag), a TTL, a view counter. It never sees: the decryption key, the recipient identity, the secret values.

§ 07· Who runs what

Sub-processors & infrastructure.

  • Vercel — web hosting and product analytics; us-east-1 (Washington, DC).
  • MongoDB Atlas — ciphertext storage and minimal metadata for team sync. Roadmap
  • Resend — transactional email (sign-in links, receipts).
  • Stripe — payment processing; PCI handled entirely on Stripe’s side.

All providers have a DPA in force.

§ 08· Found a bug?

Responsible disclosure.

Email security@justenv.app. We acknowledge new reports within 72 hours and commit to a remediation plan within 14 days for confirmed issues.

Please give us a chance to fix the issue before public disclosure. We do not currently run a paid bug bounty; we do credit reporters in the changelog when fixes ship, with permission.

PGP key: https://justenv.app/.well-known/pgp.asc Roadmap

§ 09· Lines we don't cross

What we never do.

  • We never log plaintext values, not even briefly, not even in error traces.
  • We never transmit the vault except as ciphertext, and only when you explicitly opt into team sync or share a link.
  • We never sell, rent, or share data with third parties for advertising.
  • We never add a sub-processor without updating this page first.
  • We never store cryptographic keys server-side. The vault is yours; we just rent the cabinet.