LSH is an encrypted secrets manager. The security of your secrets depends entirely on how you store your encryption key.
Why This Is Wrong:
β INSECURE: Storing the encryption key in the file it encrypts
βββββββββββββββββββββββββββββββββββββββ
β .env file contains: β
β - LSH_SECRETS_KEY=abc123... β β Encryption key
β - API_KEY=secret β β Data to encrypt
β - DATABASE_URL=postgres://... β β Data to encrypt
βββββββββββββββββββββββββββββββββββββββ
This creates a circular security flaw:
- The encryption key is stored in the same file it's meant to protect
- If
.envis accidentally committed to git, your encryption key is exposed - Anyone with the key can decrypt all your secrets
- Defeats the entire purpose of encrypted secrets management
For Individual Developers:
# Generate encryption key
lsh key
# Add to your shell profile (choose one based on your shell)
echo 'export LSH_SECRETS_KEY="your-key-here"' >> ~/.zshrc # For Zsh
echo 'export LSH_SECRETS_KEY="your-key-here"' >> ~/.bashrc # For Bash
echo 'set -x LSH_SECRETS_KEY "your-key-here"' >> ~/.config/fish/config.fish # For Fish
# Reload your shell
source ~/.zshrc # or ~/.bashrcFor Teams:
-
Generate key once:
lsh key
-
Share securely via one of these methods:
- π Password Manager (1Password, LastPass, Bitwarden)
- π Encrypted Email (ProtonMail, GPG)
- π Secure Chat (Signal, encrypted Slack DM)
- π Team Secrets Platform (HashiCorp Vault, AWS Secrets Manager)
Never:
- β Post in public Slack channels
- β Send via unencrypted email
- β Commit to git
- β Store in project files
-
Each team member adds to their shell profile:
# Each developer on their own machine echo 'export LSH_SECRETS_KEY="shared-team-key"' >> ~/.zshrc source ~/.zshrc
-
Verify setup:
lsh doctor
Before using LSH in production, verify:
-
LSH_SECRETS_KEYis NOT in your project's.envfile -
LSH_SECRETS_KEYis in your shell profile (~/.zshrc,~/.bashrc, etc.) -
.envis in your.gitignore - You can run
echo $LSH_SECRETS_KEYand see your key - All team members have the same
LSH_SECRETS_KEYin their shell profiles - The encryption key is stored in your team's password manager
For GitHub Actions, GitLab CI, etc.:
# GitHub Actions example
env:
LSH_SECRETS_KEY: ${{ secrets.LSH_SECRETS_KEY }}
# Add LSH_SECRETS_KEY to your repository secrets:
# Settings β Secrets and variables β Actions β New repository secretIf using cloud storage (Supabase/PostgreSQL):
# Store these in your shell profile too, NOT in project .env
export SUPABASE_URL="your-supabase-url"
export SUPABASE_ANON_KEY="your-anon-key"
# OR use a separate config file
~/.config/lsh/config.envRotate your encryption key periodically:
# Generate new key
NEW_KEY=$(lsh key --export | cut -d"'" -f2)
# Pull secrets with old key
lsh pull --env production
# Update shell profile with new key
echo "export LSH_SECRETS_KEY='$NEW_KEY'" >> ~/.zshrc
source ~/.zshrc
# Push with new key
lsh push --env production
# Share new key with team via secure channelFor maximum security, use different keys per environment:
# In your shell profile
export LSH_SECRETS_KEY_DEV="dev-key-here"
export LSH_SECRETS_KEY_STAGING="staging-key-here"
export LSH_SECRETS_KEY_PROD="prod-key-here"
# Use environment-specific key
LSH_SECRETS_KEY=$LSH_SECRETS_KEY_PROD lsh pull --env productionRegularly audit who has access to your encryption key:
# Check Supabase access logs
lsh env production --audit
# Review team members who have the key
# Keep a secure inventory in your password managerCritical: If you lose your LSH_SECRETS_KEY, your encrypted secrets are unrecoverable.
Backup strategies:
- Store in team password manager (1Password, LastPass)
- Print and store in physical safe
- Encrypted backup in multiple locations
- Documented in team security runbook
# NEVER set this in production
export LSH_ALLOW_DANGEROUS_COMMANDS=true
# This disables critical security validationsIf you discover a security vulnerability in LSH, please report it responsibly:
- Do NOT open a public GitHub issue
- Email: security@example.com (or create a private security advisory)
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will respond within 48 hours and provide a timeline for a fix.
LSH uses industry-standard encryption:
- Algorithm: AES-256-CBC
- Key derivation: PBKDF2 with SHA-256
- Iterations: 100,000
- Salt: Random 16-byte salt per encryption
- IV: Random 16-byte initialization vector per encryption
Key format:
- 64 hexadecimal characters (32 bytes / 256 bits)
- Generated using Node.js
crypto.randomBytes(32)
| Version | Audit Date | Auditor | Status |
|---|---|---|---|
| 1.7.x | 2025-11-23 | Internal | β Passed |
This security policy was last updated on 2025-11-23.
We review and update this policy:
- After each major release
- Following security audits
- When new threats are identified
- Based on community feedback
We follow security best practices from:
- OWASP Top 10
- NIST Cybersecurity Framework
- CIS Controls
- Industry-standard secrets management practices
Remember: Your secrets are only as secure as your encryption key. Protect it accordingly.