Architecture & Security

How envv actually works, and why your secrets are safer than SaaS alternatives.

The Core Principle

We store your secrets so teammates can sync them — but we can't read them.

envv uses end-to-end encryption where all encryption and decryption happens on your machine. Secrets are encrypted with your team's public keys before being pushed to our servers. Only team members with private keys can decrypt. Our servers store ciphertext we can't use.

Built on Battle-Tested Technology

envv is built on Mozilla SOPS (Secrets OPerationS), which has been used in production by thousands of companies since 2015. We're not reinventing cryptography - we're adding team collaboration to a proven foundation.

Foundation

  • Encryption: AES-256-GCM (NIST-approved AEAD cipher)
  • Key format: Modern age keys (simpler than PGP, auditable)
  • CLI: Built on SOPS - battle-tested since 2015
  • Backend: Handles team coordination, never sees secret values

We're still iterating on the backend architecture. Working with design partners to figure out what actually matters for 3-10 person teams.

How Encryption Works

When You Push Secrets

1. You Run
envv push .env --env prod
2. CLI Encrypts
AES-256-GCM locally
3. Uploads
Ciphertext to backend

What gets encrypted (stored in .envv/ and backend):

{ "KEY": "ENC[AES256_GCM,data:vL8t...,iv:Hg==,tag:zA==,type:str]", "sops": { "age": [ { "recipient": "age1ql3z7hjy54pw3h...", "enc": "-----BEGIN AGE..." } ], "mac": "ENC[AES256_GCM,data:3kL...]" } }

What's happening:

When You Run Your App

1. You Run
envv run -- npm start
2. CLI Decrypts
In memory only
3. Injects + Runs
Zero plaintext on disk

Team Management Architecture

The Trust Model

The backend's job: store encrypted secrets and manage team membership.

Secrets are encrypted on your machine before upload. Your private keys stay on your laptop. The backend stores ciphertext it can't decrypt and tracks which public keys belong to which projects.

What the Backend Knows

Information Stored? Why
User email ✓ Yes Account management
Team membership ✓ Yes Access control
Public keys (age/PGP) ✓ Yes Enable encryption for team
Audit logs (who, when) ✓ Yes Compliance and security
Encrypted secrets ✓ Yes Stored so teammates can sync (but we can't decrypt)
Plaintext secret values ✗ No Never sent to our servers
Private keys ✗ No Generated and stored locally

Team Workflow

Scenario: Alice wants to give Bob access to team secrets

# 1. Alice invites Bob $ envv org invite --email=bob@acme.com # What happens: # - Backend emails Bob an invite link # - Bob registers and generates age keypair LOCALLY # - Bob uploads ONLY his public key to backend # 2. Bob joins and pulls secrets $ git clone repo && cd repo $ envv project init --org-id=org_xxx --project-id=proj_xxx $ envv pull --env production # What happens: # - Encrypted secrets cached in .envv/ # - Bob can decrypt (has private key) # 3. Alice updates secrets $ envv push .env --env production # What happens: # - CLI encrypts for ALL team member public keys # - Uploads ciphertext to backend # - Bob runs `envv run` and gets new secrets

Security Properties

End-to-End Encryption

Secrets are encrypted on your machine and can only be decrypted by team members with private keys. The backend cannot decrypt your secrets even if compromised. We store encrypted secrets so your team can sync them, but we can't decrypt them. We know who's on your team and when they accessed the system — but we can't read any secret values, even if we wanted to.

Offline-First

Your app continues to work even if:

Encryption and decryption happen entirely locally. Backend is only needed for team management.

Auditable

Unlike SaaS secret managers where you trust their claims:

Audit Trail

Here's the thing about secrets: they move through your organization like water through soil. Developers pull them down at coffee shops, CI pipelines grab them at 3am, contractors access them from God-knows-where. And for most teams, that flow is invisible. A black box. You find out something went wrong only after it's already gone wrong.

We built the audit trail because we've been in that war room. The one where everyone's staring at each other asking "who had access to production?" and nobody knows. The silence is deafening. The CEO is on the call. Legal is taking notes.

Never again.

Everything Leaves a Mark

Every time someone touches your secrets — every push, every pull, every permission change — envv writes it down. Not because we're paranoid (okay, a little paranoid), but because the alternative is chaos. Here's what we capture:

Event The Story It Tells
push Someone updated secrets. Which environment? How many keys changed? New version created.
pull Someone grabbed secrets. From where? At what time? This is the one you'll query most.
rollback Someone hit undo. From which version to which? Usually means something broke.
access granted The team grew. Who got in? What can they see? Who let them in?
access revoked Someone's out. Contractor finished, employee left, trust ended. The door closed.
key rotation Someone's being careful. Old key deprecated, new key active. Good hygiene.

The Anatomy of a Log Entry

Each entry answers the questions that matter when you're under pressure:

Pulling the Thread

The API gives you what you need, how you need it. Query the whole org when you're doing compliance reviews. Drill into a single project when something smells off.

# The big picture — everything across your org GET /api/v1/organizations/:orgId/audit # Just the pulls. Who's been reading? GET /api/v1/organizations/:orgId/audit?action=pull&limit=100 # One project, full history. What happened here? GET /api/v1/projects/:projectId/audit

Paginated, filterable, exportable. Pipe it to Datadog, dump it into Splunk, build dashboards in Grafana. The data belongs to you — we just keep it safe.

When You'll Thank Yourself

You won't think about audit logs on a normal Tuesday. They're furniture. Background noise. But then comes the day — and it always comes — when you need them desperately:

The audit trail won't prevent bad things from happening. But it turns "we have no idea" into "here's exactly what happened." And in a crisis, that's everything.

Threat Model

What We Protect Against

Threat Protection
Laptop stolen Secrets encrypted at rest, private key is passphrase-protected
Git repo leaked Secrets are encrypted, useless without private keys
Backend compromised Only encrypted secrets stored, attackers get ciphertext they can't decrypt
Insider threat Audit logs track all access, remove team member = re-encrypt
Supply chain attack Builds are reproducible, binary is signed, code is open source

What We Don't Protect Against

Be honest about limitations:

Comparison to Alternatives

vs HashiCorp Vault

Vault: Centralized secret storage, requires server running 24/7

envv: Decentralized (git), works offline, no server required

vs AWS Secrets Manager

AWS: Cloud-hosted, requires internet, AWS lock-in

envv: Local-first, works offline, cloud KMS optional

vs 1Password Teams

1Password: Great for humans, not designed for CI/CD

envv: CLI-first, designed for developers and automation

vs Plain SOPS

SOPS: Manual key management, no team features

envv: Automated team management, audit logs, rotation

Compliance

envv's architecture makes compliance easier:

Enterprise plan includes compliance documentation and support.

Questions?

Security Concerns?

We take security seriously. If you've found a vulnerability, please report it via GitHub Security Advisories.

For general architecture questions: GitHub Discussions