Skip to main content

Security

Security model, threat model, and encryption details for EnvCat.

Security Overview

EnvCat is designed with a local-first, zero-trust security model. Your secrets stay on your infrastructure and are encrypted at multiple layers.

Core security principles:

  • Local-first: No cloud dependencies, no third-party trust
  • Encryption at rest: Bundle values encrypted in SQLite
  • End-to-end encryption: Server-to-CLI encryption via sealed boxes
  • Ephemeral approvals: Single-use requests with TTL
  • No plaintext storage: Server never stores plaintext secrets

Encryption Layers

EnvCat uses two layers of encryption:

Layer 1: At-Rest Encryption (Bundle Storage)

Purpose: Protect bundle values in SQLite database.

Technology: libsodium secretbox (XSalsa20 + Poly1305 MAC)

How it works:

  1. Bundle items stored in SQLite
  2. Values encrypted with server-side key (BUNDLE_KMS_KEY)
  3. Decryption happens in-memory only
  4. Encrypted values include authentication tag (tamper-proof)

Key storage: Environment variable BUNDLE_KMS_KEY (32-byte base64)

Security properties:

  • Authenticated encryption (detects tampering)
  • Nonce-based (unique nonce per encryption)
  • Server-side key required to decrypt

Trade-off: Server has access to decryption key. This enables server-side re-encryption for CLI but means the server is trusted.

Layer 2: End-to-End Encryption (CLI Communication)

Purpose: Ensure only the CLI can decrypt secrets, never the server in plaintext.

Technology: libsodium sealed boxes (X25519 + XSalsa20-Poly1305)

How it works:

  1. CLI generates ephemeral keypair (per request)
  2. CLI sends public key to server with request
  3. Server loads bundle, decrypts at-rest, encrypts to CLI public key
  4. Server stores ciphertext in Redis
  5. CLI retrieves ciphertext, decrypts with private key
  6. Private key destroyed after use

Security properties:

  • Only CLI can decrypt (server never sees plaintext)
  • Ephemeral keypairs (new keypair per request)
  • Forward secrecy (old requests can't be decrypted)
  • Anonymous encryption (server can't prove who requested)

Crypto primitives:

  • X25519 - Elliptic curve Diffie-Hellman
  • XSalsa20-Poly1305 - Authenticated encryption
  • Sealed box - One-way encryption (encrypt-only, decrypt requires private key)

Threat Model

What EnvCat Protects Against

Accidental git leaks

  • Secrets stored encrypted, not in .env files
  • Approval flow prevents copy-paste mistakes
  • CLI warns if writing .env in git repo

Database compromise

  • Bundle values encrypted at rest
  • Attacker needs BUNDLE_KMS_KEY to decrypt
  • No plaintext secrets in database

Network eavesdropping (local)

  • End-to-end encryption (CLI to server)
  • Ephemeral requests (single-use, TTL)
  • No long-lived tokens

Unauthorized access to bundles

  • Approval workflow (user must approve in browser)
  • TTL expiration (requests expire after 5 min)
  • Single-use (requests deleted after retrieval)

Insider threat (limited)

  • Server operator can't see plaintext in E2E flow
  • Database admin can't read encrypted values without key
  • Redis only stores ephemeral ciphertext

What EnvCat Does NOT Protect Against

Compromised server

  • Server has BUNDLE_KMS_KEY and can decrypt at-rest bundles
  • Mitigations: Use envelope encryption (future), hardware security module (future)

Compromised client (CLI)

  • Malware on client can steal private key from memory
  • Mitigations: Use secure hardware (future), attestation (future)

Process environment visibility

  • Variables visible in /proc/<pid>/environ (Linux)
  • Child processes inherit environment
  • Mitigations: Use ephemeral shells, unset after use

Logging and crash dumps

  • Variables may leak into logs or core dumps
  • Mitigations: Never log values (server-side), disable core dumps (client-side)

Physical access

  • Attacker with physical access can extract keys
  • Mitigations: Disk encryption, secure boot

Social engineering

  • User approves malicious request in browser
  • Mitigations: User education, audit logs (future)

Security Best Practices

Server-Side

1. Generate Strong Encryption Key

⚠️ CRITICAL: Change BUNDLE_KMS_KEY from default in production.

# Generate secure 32-byte key
openssl rand -base64 32

# Set in docker-compose.yml or .env
BUNDLE_KMS_KEY=<generated-key>

2. Protect Environment Variables

# Secure docker-compose.yml
chmod 600 docker-compose.yml

# Or use .env file
echo "BUNDLE_KMS_KEY=..." > .env
chmod 600 .env

3. Enable HTTPS (Production)

Local dev uses HTTP. Production should use HTTPS:

# docker-compose.yml (production)
web:
environment:
- NODE_ENV=production
- HTTPS=true

4. Restrict Network Access

# docker-compose.yml
services:
api:
ports: [] # Don't expose Flask API to host

redis:
ports: [] # Don't expose Redis to host

5. Regular Backups

Backup SQLite database:

docker compose exec api cp /data/app.db /data/backup.db
docker compose cp api:/data/backup.db ./backup-$(date +%Y%m%d).db

Encrypt backups:

gpg --symmetric --cipher-algo AES256 backup.db

Client-Side (CLI)

1. Secure .env Files

# Always use restricted permissions
constants request --write .env
ls -l .env
# -rw------- 1 user user (0600 perms)

2. Add .env to .gitignore

echo ".env" >> .gitignore
git add .gitignore

3. Unset Variables After Use

# Load secrets
eval "$(constants request)"

# Use secrets
./run-command

# Unset when done
unset API_KEY DB_URL

4. Use Ephemeral Shells

# Start subshell
bash -c 'eval "$(constants request)" && ./run-command'
# Secrets gone when subshell exits

5. Disable Core Dumps

# Prevent secrets leaking into core dumps
ulimit -c 0

Operational

1. Rotate Secrets Regularly

# Update bundle item
curl -X POST "http://localhost:8888/api/v1/bundles/$BUNDLE_ID/items" \
-d '{"key":"API_KEY","value":"new_key_123"}'

2. Monitor Access (Future: M10)

Audit logs will track:

  • Who requested secrets
  • Which bundles were accessed
  • When approvals occurred

3. Least Privilege

  • Create separate bundles per environment (dev, staging, prod)
  • Separate bundles per service/app
  • Don't share production bundles widely

4. Review Bundles

Periodically review:

  • Which bundles exist
  • Who has access
  • Are secrets still needed

Compliance Considerations

Data Residency

Local-first = Data stays on your infrastructure.

  • GDPR: Data in EU stays in EU
  • SOC 2: Control over data location
  • PCI DSS: Secrets on compliant infrastructure

Encryption Standards

  • At-rest: XSalsa20-Poly1305 (libsodium)
  • In-transit: HTTPS (TLS 1.3 recommended)
  • Key length: 256-bit keys

Audit Requirements

Current (M7): Basic logging (Flask access logs).

Future (M10): Comprehensive audit logs:

  • User actions (create, read, update, delete)
  • Approval events (who approved what)
  • Access patterns (which bundles accessed when)

Cryptography Details

Libraries

  • libsodium: Audited cryptography library
    • Python: PyNaCl (wrapper around libsodium)
    • Go: golang.org/x/crypto/nacl (implementation)
  • Algorithm suite: NaCl (Networking and Cryptography Library)

Encryption Modes

Secretbox (At-Rest):

  • Cipher: XSalsa20 (stream cipher)
  • MAC: Poly1305 (authentication)
  • Nonce: 24 bytes (random, unique per encryption)
  • Key: 32 bytes (from BUNDLE_KMS_KEY)

Sealed Box (End-to-End):

  • Key exchange: X25519 (Curve25519 Diffie-Hellman)
  • Cipher: XSalsa20-Poly1305
  • Ephemeral keypair: Generated per request
  • Public key: 32 bytes
  • Private key: 32 bytes (memory-only)

Key Management

Current:

  • Server-side symmetric key (env var)
  • Ephemeral CLI keypairs (in-memory)

Future (M8+):

  • Envelope encryption (per-bundle data keys + master key)
  • HSM support (hardware security module)
  • Cloud KMS integration (AWS KMS, GCP KMS, Azure Key Vault)

Reporting Security Issues

Found a security vulnerability?

DO NOT open a public issue.

Email: security@EnvCat (future)

For now: Open a private security advisory on GitHub:

  • Go to repository → Security → Advisories → New draft

What to include:

  • Description of vulnerability
  • Steps to reproduce
  • Impact assessment
  • Suggested fix (if any)

Response timeline:

  • Acknowledgment: Within 48 hours
  • Initial assessment: Within 7 days
  • Fix timeline: Depends on severity

Responsible disclosure: We'll credit you in the security advisory and release notes (unless you prefer to remain anonymous).


TODO: Security Sign-off - Confirm with security owner that crypto terminology ("sealed boxes", "secretbox") and implementation details match current codebase and security approvals.


Additional Security Resources

  • Threat Model - Detailed threat analysis
  • At-Rest Encryption - Deep dive into bundle encryption (coming soon)
  • Architecture: Data Flow - See how data flows through the system
  • SECURITY_NOTES.md - See internal docs/SECURITY_NOTES.md for security notes

External Resources: