Stop hardcoding your API keys. Stop leaking secrets to GitHub. Stop paying for a vault you don't need.
PX Secrets is a free, open-source secrets manager that runs entirely on your machine. Beautiful dark UI, CLI access, and a local API your AI agents can query at runtime — so your keys never touch code, .env files, or git history.
Encrypted with SOPS + AGE — the same encryption trusted by DevOps teams worldwide. No cloud. No subscription. No telemetry. Your secrets stay on your machine, period.
# Your agent fetches secrets at runtime — nothing hardcoded, nothing leaked
export OPENAI_API_KEY=$(python3 px_secrets.py --get openai api_key)Perfect for developers, AI builders, homelabbers, and sysadmins who want real encryption without the complexity of HashiCorp Vault or the recurring cost of 1Password.
If PX Secrets helps you sleep better at night, give it a star — it helps others find it and keeps us building free tools.
| PX Secrets | 1Password / Bitwarden | HashiCorp Vault | .env files | |
|---|---|---|---|---|
| Cost | Free forever | Subscription | Free (complex) | Free |
| Data location | Your machine only | Their cloud | Your server | Your machine |
| Encryption | SOPS + AGE (industry standard) | Proprietary | Proprietary | None |
| Setup time | 2 minutes | Account creation | Hours | Seconds |
| Network required | Never | Always | Yes (server) | No |
| GUI | Yes (web + native) | Yes | No | No |
| CLI | Yes | Yes | Yes | Manual |
| Open source | AGPL-3.0 | Partial | BSL | N/A |
PX Secrets fills the gap between "I keep my secrets in .env files" and "I need a full enterprise vault." It gives you real encryption, a clean UI, and CLI access — without any cloud dependency or complex setup.
- Local encryption — SOPS + AGE encrypt your vault on disk. Zero data leaves your machine.
- Dark GUI — Clean, dark-themed web UI with search, service grouping, and accordion cards.
- CLI access — List services, retrieve secrets by name, pipe to scripts.
- Native window — Optional pywebview mode for a desktop-app experience.
- Clipboard auto-clear — Copied secrets are wiped from clipboard after 30 seconds.
- Notes per secret — Attach context to any key (expiration dates, rotation info, etc.).
- Settings UI — Configure vault path, AGE key file, and public key from the GUI.
- Headless mode — Run as a background server for automation and LaunchAgents.
- macOS native identity — Shows as "PX Secrets" in Activity Monitor and menu bar; Dock icon hidden in headless mode.
- Single file — One Python file, no build step, no complex setup.
- Privacy by design — No telemetry, no analytics, no network calls. Ever.
- Python 3.9+
- macOS or Linux (Windows may work but is untested)
- SOPS —
brew install sopsor install from GitHub - AGE —
brew install ageor install from GitHub
# macOS (Homebrew)
brew install sops age
pip3 install flask pyyaml
# Linux
# Install sops and age from their GitHub releases, then:
pip3 install flask pyyamlOr install from the repo (handles Python dependencies automatically):
git clone https://github.com/pxinnovative/px-secrets.git
cd px-secrets
pip3 install .mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txtThis prints your public key (starts with age1...) and saves your private key to the file.
IMPORTANT: Back up your private key NOW. Open
~/.config/sops/age/keys.txt, copy the entire contents, and save it in your password manager (1Password, Bitwarden, KeePass, etc.). If you lose this key, your encrypted secrets cannot be recovered. Ever. There is no reset, no recovery, no backdoor. The private key is the only way to decrypt your vault.
python3 px_secrets.pyYour browser opens automatically to http://127.0.0.1:9999.
Important — first-time setup:
- Click Settings
- Paste your AGE public key into the "AGE Public Key" field
- Click Save
This tells SOPS which key to use for encryption. Without it, adding secrets will fail.
Click + Add, enter a service name (e.g., github), a key name (e.g., token), and the secret value. PX Secrets creates an encrypted vault at ~/secrets/vault.enc.yaml.
PX Secrets can also run headless as a long-lived background service — useful when scripts, agents, or other tools on the same host need to fetch secrets from the local API without you keeping a desktop session open.
A Dockerfile is included in the repo. Build and run:
docker build -t px-secrets:dev .
docker run -d --name px-secrets \
-p 127.0.0.1:9999:9999 \
-v /path/to/your/vault.enc.yaml:/vault/vault.enc.yaml:ro \
-v /path/to/your/age-key:/app/.config/sops/age/keys.txt:ro \
-e PX_SECRETS_HOST=0.0.0.0 \
-e PX_SECRETS_READ_ONLY=1 \
px-secrets:devThe image carries no secrets — your vault file and AGE key are bind-mounted at runtime. Make sure the AGE key file is mode 0400 on the host so the runtime user (uid 10001) can read it but nothing else can.
| Variable | Purpose | Default |
|---|---|---|
PX_SECRETS_HOST |
Bind address. Set to 0.0.0.0 inside a container so port mapping works; leave unset on a workstation to keep the listener on localhost. |
unset (binds to localhost) |
PX_SECRETS_READ_ONLY |
When set to 1 / true / yes, the six mutating endpoints (POST/DELETE /api/secret, DELETE /api/service, POST /api/note, POST /api/settings, POST /api/import) return HTTP 403. Reading endpoints continue to work. Useful for daemon mode. |
unset (writes allowed) |
PX_SECRETS_AUTH_TOKEN |
When set, every request to /api/* must include Authorization: Bearer <token> (constant-time compared). Useful for multi-process hosts where you want a non-human caller (script, agent, sidecar) to authenticate against the API on the same loopback port. The UI prompts for the token on the first 401 and caches it in sessionStorage for the rest of the tab. |
unset (open API on loopback) |
- Long-lived daemon serving secrets to scripts on the same host: enable
PX_SECRETS_READ_ONLY=1. Do edits from a separate, short-lived interactive session. - Container behind a reverse proxy with no UI auth: enable read-only at minimum; consider also fronting with an auth gateway since the API has no built-in authentication.
- Interactive desktop use: leave read-only off.
The local API is unauthenticated by default — its security boundary is the host itself. Never expose port 9999 outside the local host or a trusted private network without authentication. Two options for hardening:
- Set
PX_SECRETS_AUTH_TOKEN(see env table above) so every/api/*request must carry a matchingAuthorization: Bearerheader. Suitable for multi-process hosts where you trust the host but not every process on it. - For internet exposure, front with an authentication gateway (Authelia, oauth2-proxy) plus a TLS-terminating reverse proxy. The bearer token can stack on top so the API rejects requests even if the gateway is bypassed.
python3 px_secrets.py # Opens in browser
python3 px_secrets.py --native # Opens in native window (requires pywebview)
python3 px_secrets.py --headless # Server only, no browser
python3 px_secrets.py --port 8888 # Custom portpython3 px_secrets.py --list # List all services and keys
python3 px_secrets.py --get github token # Print a secret value (for scripting)Pipe to clipboard:
python3 px_secrets.py --get aws secret_key | pbcopy # macOS
python3 px_secrets.py --get aws secret_key | xclip # LinuxOn first run, click Settings to configure:
| Setting | Default | Description |
|---|---|---|
| Vault File Path | ~/secrets/vault.enc.yaml |
Where your encrypted vault lives |
| AGE Key File | ~/.config/sops/age/keys.txt |
Your private AGE key for decryption |
| AGE Public Key | (empty — must be set) | Your public AGE key for encryption |
Settings are saved to ~/.px-secrets/config.json.
- You add a secret through the UI or API
- PX Secrets writes the data to a temporary YAML file
- SOPS encrypts the file using your AGE public key
- The encrypted vault is saved to disk
- The temporary file is deleted immediately
Reading secrets reverses the process — SOPS decrypts using your AGE private key, PX Secrets parses the YAML, and the decrypted data is only ever held in memory.
Your AGE private key never leaves ~/.config/sops/age/keys.txt. SOPS reads it directly — PX Secrets never touches it.
- No network calls — PX Secrets never contacts any server, ever
- No telemetry — No analytics, no usage tracking, no crash reports
- No cloud — Your vault is a local file, encrypted with keys you control
- Clipboard auto-clear — Secrets copied to clipboard are wiped after 30 seconds
- Temp file cleanup — Decrypted data is never written to disk permanently
- 127.0.0.1 only — The web server binds to localhost, inaccessible from the network
PX Secrets isn't just for humans — it's designed to keep your AI agents, automation scripts, and CI/CD pipelines safe from secret leaks.
Every day, API keys and tokens end up exposed because developers:
- Hardcode them in scripts (
OPENAI_API_KEY = "sk-...") - Store them in
.envfiles that accidentally get committed to GitHub - Pass them as environment variables that show up in logs
- Copy-paste them into AI agent configs that get shared or versioned
One leaked key can cost thousands of dollars or compromise your entire infrastructure.
Run PX Secrets in headless mode and let your agents query secrets at runtime — nothing is ever written to code, .env files, or git history.
# Your agent fetches the key at runtime — never stored in code
export OPENAI_API_KEY=$(python3 px_secrets.py --get openai api_key)
# Use in any script
curl -H "Authorization: Bearer $(python3 px_secrets.py --get github token)" \
https://api.github.com/userimport requests
# Your agent queries PX Secrets locally — no .env file needed
vault = requests.get("http://127.0.0.1:9999/api/vault").json()
api_key = vault["openai"]["api_key"]
# Use the key — it only exists in memory, never on disk
client = OpenAI(api_key=api_key)| Without PX Secrets | With PX Secrets |
|---|---|
sk-abc123... hardcoded in your script |
Secret fetched at runtime, never in code |
.env file with all your keys |
No .env file needed |
| Keys in git history forever (even after deletion) | Nothing to commit — vault is separate and encrypted |
| Agent configs with plaintext tokens | Agent queries localhost API, gets key in memory only |
One leaked .env = all secrets exposed |
Vault is encrypted — useless without your AGE key |
Tip: Run
python3 px_secrets.py --headlessas a background service. Your agents can queryhttp://127.0.0.1:9999/api/vaultwhenever they need a secret — zero risk of leaking credentials into code or logs.
For a desktop-app experience without a browser tab:
pip3 install pywebview
python3 px_secrets.py --nativeCreate a LaunchAgent to start PX Secrets automatically:
cat > ~/Library/LaunchAgents/com.pxsecrets.headless.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.pxsecrets.headless</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>/path/to/px_secrets.py</string>
<string>--headless</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.pxsecrets.headless.plist- Star this repo if PX Secrets is useful to you
- Join the conversation in GitHub Discussions
- Report bugs or request features in GitHub Issues
- Share your experience — we want to hear how you use it
- PRs welcome — see CONTRIBUTING.md
We're building in public and we want your input. PX Secrets is part of PX Open Suite — a collection of free, local-first tools for developers and creators.
v1.2.0 — Initial Release
- Dark GUI with search and service grouping
- CLI access (
--list,--get) - Headless mode for background service
- Native window mode (pywebview)
- Clipboard auto-clear (30s)
- Notes per secret
- Configurable vault path, AGE key, and port
v1.3.0 — Generator & Import/Export
- Built-in key & password generator — 9 categories, cryptographically secure
- Import/export secrets — .env, JSON, YAML (auto-detect)
v1.4.0 — Installer & UI Improvements
- One-command installer (
install.sh) - Settings: mask sensitive values (AGE key, key file path)
- Header icon sizing + star moved to footer
v1.4.1 — macOS Native Identity & About Dialog
- macOS app identity — process name, menu bar, Activity Monitor
- Dock icon hidden in headless mode
- About dialog with version, runtime, and system info
- Keyboard shortcuts (Cmd+K search, Escape close, Cmd+N add)
v1.5.0 — Headless / Container deployment (shipped in v1.5.1 release)
- Official Docker image with PX_SECRETS_HOST env
- Read-only mode via PX_SECRETS_READ_ONLY
- Deploy-as-a-service README section
- Refuse silent overwrite of existing secrets
v1.5.1 — Data integrity and UI honesty
- Case-insensitive service dedup on add/delete/note/import
- Service names render with their stored casing — the UI no longer force-uppercases display, so what you see in the list matches exactly what was saved
v1.6.0 — Foundation: self-update + API auth
- Self-update from the GitHub Releases API —
Check for updatesbutton in the About dialog, single-file replacement, backup-on-rollback, process restart via LaunchAgent / systemdKeepAlive - Bearer token authentication for
/api/*viaPX_SECRETS_AUTH_TOKEN— unblocks safe API exposure for non-human callers on multi-process hosts; UI prompts on 401 and caches the token in sessionStorage
v1.6.1 — Auth-exempt health endpoints
- Adds
/healthz(liveness) and/readyz(readiness, exercises the SOPS+AGE decrypt chain) outside the/api/prefix so Kubernetes / systemd probes don't 401 whenPX_SECRETS_AUTH_TOKENis set
v1.6.2 — Dockerfile no longer hard-codes read-only mode
-
PX_SECRETS_READ_ONLYremoved as a DockerfileENVdefault — security policy is a deployment concern, not an image concern. Writable is the default; pass-e PX_SECRETS_READ_ONLY=1(or set in the K8s manifest) when you want a read-only sidecar. Previously the bake-in made it impossible to deploy a writable pod without an explicit override-to-empty in every manifest.
Future
Data model & UX
- Nested secrets with multiple fields, multi-account services, ordered sequences
- Typed secrets with filter, sort, and selective import/export per type
- Inline edit for value (and note) — shipped v1.7.0 (key_name rename / key_type still open)
- Multiple named vaults with per-vault access control
Security & key management
- AGE key custody flow at onboarding + key rotation support
- Optional UI unlock layer with auto-lock on idle — shipped v1.7.0 (master password; Touch ID / WebAuthn still open)
- Per-secret rotation with safety confirmation
- 2FA backup codes (TOTP recovery codes)
- Bearer token for multi-process hosts (discussion)
Platform & distribution
- Native macOS .app bundle with custom icon (Phase 2)
- Onboarding wizard (first-run setup with key generation)
- Self-update from GitHub
- Homebrew cask (
brew install --cask px-secrets)
See Issues for the full list.
- Bug reports: GitHub Issues
- Questions & ideas: GitHub Discussions
- Buy me a coffee: buymeacoffee.com/pxinnovative
- Star the repo — it helps more than you think
AGPL-3.0 — free to use, modify, and distribute. If you distribute a modified version, you must share the source.
"PX Secrets" is a trademark of PX Innovative Solutions Inc. — see TRADEMARK.md.
Made with 🔐 by Victor Kerber @ PX Innovative Solutions Inc.