Phantom gives Claude and other AI coding tools a secrets vault that refuses to expose real API keys. The MCP server lets agents list, rotate, and check secrets without ever seeing plaintext values. Real keys live in your OS keychain, agents see worthless phm_ tokens, and a local proxy swaps them at the network layer when your code makes actual API calls. You get phantom_doctor for diagnostics, phantom_rotate for key rotation, and phantom_sync for encrypted cloud backup. Setup writes the right config file for Claude Code, Cursor, Windsurf, or Codex. All mutating operations require an explicit confirm parameter so prompt injection can't silently delete your Stripe key. Use it when you want to hand Claude your entire codebase without also handing it your production credentials.
Delegate everything to AI. Without sharing a single key.
Phantom hands every AI tool a worthless phm_ token. The local proxy injects the real key at the network layer. Full access. Zero exposure.
Quick start · Why Phantom? · MCP setup · Docs · phm.dev
▶ Watch the 45-second demo · 🛡 Security model · 📋 Threat model · 💬 Discussions
AI coding agents read your .env files. Once a real API key enters an LLM's context window, it leaks — via prompt injection, session logs, malicious MCP servers, or training data. GitGuardian reports AI-assisted commits leak secrets at 2× the baseline rate.
Every other secrets manager protects keys at rest and in transit. Phantom protects them in context:
.env contains only phm_ tokens; the proxy swaps them at the network edge.npx phantom-secrets init and you're protected. No accounts, no DNS, no MITM cert dance..env.Used by developers who don't want to choose between delegating to AI and not pasting their Stripe key into a chat window.
$ npx phantom-secrets init
# Auto-detects .env, .env.local, or .env in subdirectories
# Stores real secrets in OS keychain, rewrites .env with phantom tokens
# Auto-configures Claude Code MCP server if detected
$ phantom agent doctor
# One human-readable readiness check for AI-agent safety
$ phantom exec -- claude
# Authenticated proxy running on 127.0.0.1:54321
# AI sees phantom tokens; proxy injects real keys
The same commands work on Windows. npx phantom-secrets init installs via npm as on macOS/Linux.
After phantom start --daemon, the CLI detects your shell and prints the matching env-var syntax. For reference:
PowerShell:
$env:OPENAI_BASE_URL = "http://127.0.0.1:PORT/openai/_phantom/TOKEN/"
$env:PHANTOM_PROXY_PORT = "PORT"
$env:PHANTOM_PROXY_TOKEN = "TOKEN"
cmd.exe:
set OPENAI_BASE_URL=http://127.0.0.1:PORT/openai/_phantom/TOKEN/
set PHANTOM_PROXY_PORT=PORT
set PHANTOM_PROXY_TOKEN=TOKEN
Git Bash / WSL: use the export X=Y syntax from the main quick-start.
Notes:
PHANTOM_PROXY_TOKEN is the proxy session authenticator. By default, phantom exec and phantom start include it in local *_BASE_URL values as /_phantom/TOKEN/ so unmodified SDKs work. Header-aware clients can set PHANTOM_PROXY_HEADER_AUTH_ONLY=1 and send x-phantom-proxy-token: $PHANTOM_PROXY_TOKEN instead.phantom.exe fails to run with "Application Control policy has blocked this file," Windows Smart App Control is honoring the downloaded file's Mark-of-the-Web tag. One-time fix from PowerShell: Get-ChildItem "$env:USERPROFILE\.phantom-secrets\bin\*.exe" | Unblock-File.phantom init is a #!/bin/sh script. Native git from the command line invokes it via Git for Windows' bundled sh.exe, which is what the official Git for Windows installer ships. GUI clients (GitHub Desktop, some IDE integrations) may run with a stripped-down PATH that lacks sh.exe and silently skip the hook — for these, run commits from a terminal, or use phantom check --staged directly. CI is the durable safety net regardless. .env file (safe to leak) OS Keychain / Vault
+--------------------------+ +---------------------+
| OPENAI_API_KEY=phm_a7f3 | ---> | sk-real-secret-key |
| STRIPE_KEY=phm_c9d1... | | sk_live_real-key... |
+--------------------------+ +---------------------+
| |
v v
AI Agent (Claude, Cursor) Phantom Proxy (127.0.0.1)
+--------------------------+ +------------------------------+
| Reads .env | | Intercepts HTTP requests |
| Sees only phm_ tokens | ---> | Replaces phm_ with real keys |
| Makes API calls to proxy | | Forwards over TLS to real API|
+--------------------------+ +------------------------------+
phantom init reads .env, stores real secrets in the OS keychain, rewrites .env with phm_ tokensphantom exec -- claude starts a local reverse proxy, sets SDK-compatible service base URLs such as OPENAI_BASE_URL=http://127.0.0.1:PORT/openai/_phantom/TOKEN/, exposes PHANTOM_PROXY_TOKEN to the child process, and launches the commandPhantom ships an MCP server so AI coding tools can manage secrets directly -- without ever seeing real values.
phantom_list_secrets, phantom_status, phantom_init, phantom_add_secret_interactive, phantom_add_secret (deprecated; refuses plaintext), phantom_remove_secret, phantom_rotate, phantom_copy_secretphantom_doctor, phantom_why, phantom_check, phantom_envphantom_wrap, phantom_unwrap, phantom_sync, phantom_cloud_push, phantom_cloud_pull, phantom_cloud_statusphantom_team_list, phantom_team_create, phantom_team_members, phantom_team_invite, phantom_team_key_publish, phantom_team_vault_push, phantom_team_vault_pullMutating tools require an explicit confirm: true parameter so a prompt-injected agent can't silently mutate state. Real secret values are never accepted as MCP tool arguments; new secrets are entered out-of-band in a trusted terminal.
One command per AI client — Phantom writes the right config file in the right place:
phantom setup --client claude # .claude/settings.local.json (project)
phantom setup --client cursor # ~/.cursor/mcp.json
phantom setup --client windsurf # ~/.codeium/windsurf/mcp_config.json
phantom setup --client codex # ~/.codex/config.toml
phantom setup --client claude --print # snippet to stdout for any other client
If phantom-mcp isn't on PATH, Phantom falls back to npx -y phantom-secrets-mcp so the config still works on a fresh machine. Restart the AI tool after running phantom setup so it picks up the new config.
Phantom works with any tool that supports the Model Context Protocol.
Sync vaults across machines with end-to-end encryption. The server never sees plaintext.
$ phantom login
# Opens GitHub OAuth (device code flow)
$ phantom cloud push
# Encrypted client-side, uploaded to phm.dev
$ phantom cloud pull # on another machine
# Downloaded and decrypted locally
$ phantom open
# Opens https://phm.dev/dashboard — read-only view of your projects,
# vault sizes, last sync, plan tier, and team membership.
Cloud sync uses ChaCha20-Poly1305 with a client-side passphrase derived via Argon2id. The server stores only ciphertext.
Multiple developers can share a single E2E-encrypted vault per project. Server only ever stores ciphertext + per-member ciphertext shares.
$ phantom team create "engineering"
# Creates a team; you become the owner.
$ phantom team invite <team_id> <github-username>
# Invites by GitHub login.
$ phantom team key-publish <team_id>
# Registers your X25519 public key on the team.
# (Run once per team; the private key stays in the OS keychain.)
$ phantom team vault-push <team_id>
# Encrypts the current project's vault with a fresh symmetric key,
# wraps that key (X25519 + ChaCha20-Poly1305) for every member that
# has a registered public key, then uploads.
$ phantom team vault-pull <team_id> # on a teammate's machine
# Pulls, decrypts the per-member share with their private key,
# decrypts the vault, writes secrets locally.
Team memberships and member lists are visible in the read-only dashboard at phm.dev/dashboard/team.
| Command | Description |
|---|---|
phantom init | Import .env secrets into vault, rewrite with phantom tokens. --all <DIR> protects every git repo with a .env under <DIR> in one go (with --dry-run to preview, --jobs N / -j N to control parallelism) |
phantom exec -- <cmd> | Start an authenticated proxy and run a command with secret injection |
phantom start / stop | Manage proxy lifecycle (standalone/daemon mode) |
phantom list | Show secret names stored in vault (never values; --json for machine-readable output) |
phantom add <KEY> [VAL] | Add a secret. With no VAL, prompts silently on the terminal; or pipe via --stdin |
phantom remove <KEY> | Remove a secret from the vault |
phantom reveal <KEY> | Print a secret value (or --clipboard to copy) |
phantom status | Show proxy state, vault info, and mapped services |
phantom rotate | Regenerate all phantom tokens (old ones become invalid) |
phantom doctor | Check configuration and vault health (--fix to auto-repair). Reports install source, vault backend, audit-log status, Argon2 params, and MCP wiring per client |
phantom agent report | Emit a read-only AI-agent readiness report (--json for automation). Reports unsafe, protected, verified, team-ready, or compliance-ready |
phantom agent doctor | Human-readable agent readiness view backed by the same policy engine |
phantom agent setup | Preview or apply safe defaults for agent use (--dry-run first, --apply to write changes) |
phantom check | Scan for unprotected secrets (pre-commit hook, --staged, --runtime) |
phantom sync | Push secrets to Vercel / Railway (--dry-run --json previews safely; --only PATTERN filters by glob, repeatable) |
phantom pull | Pull secrets from Vercel / Railway into vault |
phantom setup | Wire Phantom into an AI client. --client claude (default), cursor, windsurf, or codex. Add --print to emit the config snippet to stdout |
phantom env | Generate .env.example for team onboarding |
phantom export | Export vault to encrypted backup file (--passphrase), or emit plaintext JSON to stdout (--json --allow-plaintext) |
phantom import | Import from encrypted backup (<FILE> --passphrase), or migrate from --from doppler|infisical|dotenvx|1password|env --file <path>. Add --force to overwrite existing secrets |
phantom audit show | Print recent audit events (--last N, --op OP, --name NAME, --json). Requires PHANTOM_AUDIT=1 |
phantom audit tail | Follow the audit log live (--op, --name filters) |
phantom audit path | Print the absolute path to the audit log file |
phantom audit verify | Verify HMAC-SHA256 chain integrity; exits 1 if tampering detected |
phantom login | Authenticate with Phantom Cloud via GitHub OAuth |
phantom logout | Clear cloud credentials |
phantom cloud push | Push encrypted vault to Phantom Cloud |
phantom cloud pull | Pull and decrypt vault from Phantom Cloud |
phantom wrap | Wrap package.json scripts with phantom exec automatically |
phantom unwrap | Restore original package.json scripts |
phantom watch | Watch .env files and auto-detect new unprotected secrets |
phantom why <KEY> | Explain why a key is or is not protected |
phantom copy <KEY> | Copy a secret to another project's vault |
phantom team list/create/members/invite | Team vault management |
phantom team key-publish <id> | Register your X25519 pubkey on a team (once per team) |
phantom team vault-push <id> | Push current project to shared team vault (E2E encrypted per-member) |
phantom team vault-pull <id> | Pull team vault into local vault |
phantom open [page] | Open phm.dev pages in browser (dashboard, billing, team, docs, github, …) |
phantom upgrade | Self-replace this binary with the latest GitHub release (--check-only to inspect first) |
phantom completion <shell> | Print a shell-completion script (bash, zsh, fish, powershell, elvish) |
phm_ placeholders in .env, rotatable on demandPHANTOM_PROXY_TOKEN; CLI-generated SDK URLs include it for compatibility, and header-aware clients can opt into x-phantom-proxy-token with PHANTOM_PROXY_HEADER_AUTH_ONLY=1text/* and application/x-www-form-urlencoded request bodies, phantom tokens are replaced frame-by-frame without buffering the full payload; a 67-byte carry buffer handles tokens that straddle chunk boundaries. JSON bodies use a buffered path to preserve field-level F9 scoping.*_KEY, *_TOKEN, sk-*, ghp_*) from config (NODE_ENV, PORT)--passphrase); plaintext JSON export to stdout (--json --allow-plaintext); import from Doppler, Infisical, dotenvx, 1Password, or plain .env via --fromPHANTOM_AUDIT=1 writes vault events as JSONL to ~/.phantom/audit.log. Each entry is chained with HMAC-SHA256; phantom audit verify detects tampering. phantom audit show/tail/path for log access.phantom wrap patches package.json so every npm script runs through the proxyphantom watch monitors .env files for new unprotected secretsphantom init --all <DIR> protects every git repo with a .env under <DIR> in one command (with --dry-run); --jobs N controls parallelismphantom setup --client claude|cursor|windsurf|codex writes the right MCP config for each AI tool, or --print for a generic snippetphantom agent doctor and phantom agent report --json answer whether a repo is safe for Claude Code, Codex, Cursor, Windsurf, and other agentsphantom doctor reports install source, vault backend, audit-log status, Argon2 params, and MCP wiring per clientphantom why <KEY> explains detection heuristicsphantom copy shares secrets between project vaults.phantom.toml$ npm install -g phantom-secrets
Or use directly with npx:
$ npx phantom-secrets init
$ claude mcp add phantom-secrets-mcp -- npx phantom-secrets-mcp
$ cargo install phantom-secrets
5-crate Rust workspace + Next.js cloud backend:
| Crate | Role |
|---|---|
phantom-core | Config (.phantom.toml), .env parsing/rewriting, token generation, auth, cloud client |
phantom-vault | VaultBackend trait: OS keychain + encrypted file fallback, ChaCha20-Poly1305 crypto |
phantom-proxy | HTTP reverse proxy on 127.0.0.1. Streaming token replacement for text/*/form bodies; buffered+scoped replacement for JSON. SSE/streaming preserved. TLS forwarding. |
phantom-cli | clap-based CLI binary with agent readiness, proxy lifecycle, audit, import/export, sync, and team workflows |
phantom-mcp | MCP server binary (rmcp SDK), stdio transport, 25 tools |
apps/web -- Next.js backend at phm.dev for cloud vault sync, GitHub OAuth, and Stripe billing.
npm packages: phantom-secrets (CLI), phantom-secrets-mcp (MCP server).
CI runs the Rust test suite and clippy across the workspace before release.
phm_ prefix ensures they never collide with real API key formatszeroize crateSee SECURITY.md for the responsible disclosure policy and THREAT_MODEL.md for the full threat model (assets, actors, mitigations, known gaps, cryptography summary).
| Free | Pro | Enterprise | |
|---|---|---|---|
| Local vaults | Unlimited | Unlimited | Unlimited |
| Cloud vaults | 1 | Unlimited | Unlimited |
| MCP server | Yes | Yes | Yes |
| Cloud sync | Yes | Yes | Yes |
| Team features | -- | -- | Yes |
| Price | $0 | $8/mo | Contact us |
We love PRs. Start with CONTRIBUTING.md, pick a good first issue, or open a discussion to talk through an idea. Be excellent to each other — see CODE_OF_CONDUCT.md.
If Phantom saves you from leaking a key — or even just from worrying about it — please star the repo ⭐. It's the single biggest signal we use to know what to build next.
MIT — see LICENSE.