CruxVault is a developer-first tool for managing secrets, configs, and feature flags, basically everything you don’t want leaking to the internet. Built with Python, it encrypts your data with AES-256-GCM (because “just trust me” is not a security strategy), keeps version history so you can undo your mistakes!
Whether you’re wrangling local dev secrets or juggling production chaos, CruxVault keeps your sensitive data safe, consistent, and slightly less terrifying!
Available in 2 flavors - CruxVault CLI and CruxVault Python API
AES-256-GCM Encryption - Military-grade encryption for all secrets at rest
Local SQLite Storage - Fast, reliable, offline-first storage
Version History - Track changes and rollback to any previous version
Tags & Organization - Organize secrets with tags and hierarchical paths
Audit Logging - Comprehensive audit trail of all operations
System Keychain Integration - Secure master key storage
Git-like Interface - Intuitive commands that feel natural
Development Mode - Generate fake secrets for local development
Import/Export - Work with .env files seamlessly
git clone https://github.com/athishrao/crux-vault.git
cd crux-vault
Initialize Cruxvalt in the current directory. Creates .cruxvalt/ directory with configuration and storage.
Set a secret value. Creates a new secret or updates an existing one.
# Basic usage
crux set api/key "abc123"# With tags
crux set stripe/key "sk_test_..." --tag production --tag payment
# Different types
crux set database/host "localhost" --type config
crux set feature/new_ui "true" --type flag
# JSON output
crux set api/key "value" --json
Retrieve a secret value.
# Basic usage
crux get database/password
# JSON output
crux get database/password --json
# Quiet mode (for piping)
crux get database/password --quiet | pbcopy
List all secrets, optionally filtered by path prefix.
# List all secrets
crux list
# Filter by prefix
crux list database/
# Show actual values (hidden by default)
crux list --show-values
# JSON output
crux list --json
# Unset all secretseval$(crux unset-env)# Unset by prefixeval$(crux unset-env database/)# Unset by tageval$(crux unset-env --tag production)# Different shellseval$(crux unset-env --format fish)
Use case - switch environments:
# Load production secretseval$(crux shell-env --tag production)# Done with prod, clean upeval$(crux unset-env --tag production)# Load dev secretseval$(crux shell-env --tag development)
Detect hardcoded secrets in your codebase.
# Scan current directory
crux scan .# Scan specific path
crux scan src/
# Scan single file
crux scan config.py
What it detects:
API keys and tokens
Passwords in code
Private keys
AWS credentials
Database connection strings
JWT tokens
Example output:
⚠ Potential secrets found:
config.py:12 - Possible API Key
utils.py:45 - Possible Password
.env.backup:3 - AWS Access Key
CruxVault supports dynamic variable expansion using ${VAR} syntax. Variables are resolved at read-time, so updates automatically propagate.
# Set base URL
crux set API_URL 'https://api.example.com'# Reference it in other secrets
crux set USERS_ENDPOINT '${API_URL}/v1/users'
crux set POSTS_ENDPOINT '${API_URL}/v1/posts'# Get expanded value
crux get USERS_ENDPOINT
# Output: https://api.example.com/v1/users# Update base URL
crux set API_URL 'https://api.production.com'# Dependent secrets automatically updated
crux get USERS_ENDPOINT
# Output: https://api.production.com/v1/users
Nested expansion:
crux set DB_HOST "localhost"
crux set DB_PORT "5432"
crux set DB_CONN 'postgresql://${DB_HOST}:${DB_PORT}'
crux set FULL_CONN '${DB_CONN}/myapp'
crux get FULL_CONN
# Output: postgresql://localhost:5432/myapp
Notes:
Bash is notorious for exanding Vars before running the cmd, use single quotes ONLY when using Variables
Variables expand recursively
Circular references are detected and raise an error
Missing variables are left as-is: ${MISSING} stays ${MISSING}
Raw values stored encrypted; expansion happens on read
Use CruxVault programmatically in your Python applications.
importosimportcruxvaultascrux# Load all secrets into environmentforsecretincrux.list():
env_var=secret['path'].upper().replace('/', '_')
os.environ[env_var] =crux.get(secret['path'])
try:
value=crux.get("nonexistent/key")
exceptFileNotFoundError:
print("Secret not found")
exceptExceptionase:
print(f"Error: {e}")
Method
Description
Returns
get(path)
Retrieve secret value
str
set(path, value, tags=[])
Store/update secret
None
delete(path)
Delete secret
bool
list(prefix=None, pretty=False)
List secrets
list[dict] or None
history(path)
Get version history
list[dict]
rollback(path, version)
Restore old version
None
Algorithm: AES-256-GCM (Authenticated Encryption)
Key Storage: System keychain via keyring library
Fallback: Environment variable UNIFIED_MASTER_KEY
Nonce: Random 96-bit nonce for each encryption
At Rest: All secret values encrypted before storage
First Priority: System keychain (macOS Keychain, Windows Credential Manager, etc.)
Second Priority: Environment variable UNIFIED_MASTER_KEY
Fallback: Auto-generated key (saved to keychain if available)
# Set master key manuallyexport UNIFIED_MASTER_KEY="<base64-encoded-key>"
All operations are logged to .cruxvault/audit.log in JSON Lines format:
# Run all tests
pytest
# Run specific test file
pytest tests/test_crypto.py
Crux secrets live in your git repo, encrypted. Your team
uses git for syncing, just like code.
Wrong merges in case of conflicts should not be an issue, history intact - easily revertable.
One person: crux init --shared && crux keygen > team.key
Share team.key securely (1Password, etc.)
Everyone: crux import-key team.key
Use git normally: commit, push, pull
That's it. No servers, no accounts, no new workflows.