vallkey
v0.9.0
Published
Replace the API keys in your project with ghost keys that only work within your rules.
Maintainers
Readme

vallkey
Swap the API keys in your project for ghost keys: stand-in keys that only work within your rules, and that you can kill in one click.
Needs Node.js 18 or newer. No dependencies.
npx vallkey login # approve this computer in your browser, once
npx vallkey init # swap the keys in your .env files for ghost keysCommands
| Command | What it does |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| login | Opens your browser to approve this computer. The tool gets its own API token, which you can revoke in Settings → API tokens. |
| init [files] | Finds API keys in your .env files, creates a ghost key for each one, and writes the ghost keys back in place of the real ones. Adds OPENAI_BASE_URL, ANTHROPIC_BASE_URL or GROQ_BASE_URL so those SDKs need no code change, prints the one line to change for the others in your project's language, and offers to run connect. --dry-run shows what it would do. |
| scan [paths] | Looks for API keys in your code and .env files; --history also looks through every commit. Keys are shown masked. Exits with 1 if it finds any. |
| keys | Lists your ghost keys. |
| keys add --from <id> | Makes another ghost key for a real key shared by several ghost keys, inside its outer rules. |
| real-keys | Lists the real keys shared by several ghost keys. |
| domains | Lists your own API domains, such as api.yourcompany.com; domains check <domain> checks one. init uses your default domain for the address it writes. |
| kill <key id> | Stops a ghost key everywhere, right away. |
| mcp | Runs the MCP server for AI coding agents (see below). |
| connect [language] | Connects the project with no code changes: installs the vallkey package (in a Python project, into its virtual environment and requirements.txt), loads it from what really starts the app (the start script, every Procfile process, the Dockerfile, railway.json, railway.toml, render.yaml, Vercel functions or the Next.js setup file), and downloads native files where needed. Asks before each change. --print only shows the steps; without a terminal it only shows them unless you pass --yes. |
| doctor | Checks local gateway configuration and Node/Bun package readiness. --json returns structured checks. It does not inspect a deployed process. |
| verify | Waits for requests from your app with the ghost keys in this project's .env files and shows each one as it arrives, with no request ID to copy. --timeout waits up to 600 seconds (default 120). With <key id> --request-id <id> it checks one exact request instead; --expect denied verifies a blocked one. No provider calls are generated. |
| hook [language] | The setup step of connect, under its former name. |
| status [key id] | Shows every app each ghost key is used from (Vercel, AWS Lambda, a laptop…), with today's requests and anything wrong. Exits with 1 if one is failing, so a deploy script can stop on it. |
| whoami, logout | Shows or removes the saved sign-in. |
Your real keys are stored encrypted and removed from the files, and Vallkey never shows a real key again. If you use one anywhere else, keep a copy in your password manager.
A line that only looks like a key can be skipped with a vallkey:ignore comment on it.
Historical false positives can use scan --history --allowlist <file>. The JSON
file contains entries with path, sha256 (the complete matched value's digest),
and a required reason. Exceptions match only that exact value in that exact
relative file path; review them like changes to the scanner itself.
Supported SDKs without changing their calls
Start with npx vallkey connect: it detects the project, recommends an address setting where the detected Node/Bun SDKs read one, and otherwise sets up auto-connect, asking before each change. Its recommendation only covers detected clients; review other clients separately. --method address or --method hook chooses explicitly, and --print only shows the steps.
Auto-connect sends requests that carry a ghost key to Vallkey through the usual HTTP clients, with no code changes. connect detects the language, installs the package or downloads any file it needs (checksum verified), and edits what starts the app, or prints the one setting to add, with Docker lines where needed. A start command set only in a host's dashboard cannot be seen from the project, so set it there too; vallkey verify shows whether it worked. If that setting already has a value, add to it instead of replacing it. On Next.js it adds a small setup file (instrumentation.ts); Edge routes need the SDK address setting. Check one request from your deployed app.
| Language | What it sets |
| ------------------- | ---------------------------------------------------------------------------------- |
| Node.js | NODE_OPTIONS='--require vallkey/auto' (Next.js: an instrumentation.ts instead) |
| Bun | BUN_OPTIONS='--preload vallkey/auto' |
| Python | VALLKEY_AUTO=1 (with pip install vallkey) |
| Ruby | RUBYOPT=-rvallkey/auto (with bundle add vallkey) |
| Java, Kotlin, Scala | JAVA_TOOL_OPTIONS=-javaagent:/path/vallkey-agent.jar |
| .NET | DOTNET_STARTUP_HOOKS=/path/Vallkey.Auto.dll |
| PHP | PHP_INI_SCAN_DIR=:/path/to/its/ini/folder |
| Elixir, Erlang | ELIXIR_ERL_OPTIONS / ERL_FLAGS with an -eval that loads it |
Set VALLKEY_ENV=production (or staging, eu-workers…) in each app to tell them apart in the dashboard and in vallkey status.
In Node.js load it before SDK imports: require('vallkey/auto') or import 'vallkey/auto'. It covers global fetch and exported Node http/https functions. Direct Undici APIs, HTTP/2, native networking and previously captured functions are not covered. VALLKEY_DEBUG=1 logs source/destination origins only; VALLKEY_AUTO=0 disables interception.
Auto-connect for Node.js and Bun checks VALLKEY_API when the app starts, and follows a value set later, as dotenv does: HTTPS origin only, with HTTP allowed for loopback tests. A value that is invalid at startup stops the app; one that turns invalid later is ignored with a warning. It detects header/query credentials, Basic authentication, string bodies, URLSearchParams and byte buffers. Request-object body inspection uses a clone and is limited to 64 KiB and 200 ms. Streaming/body-only authentication outside that window, multipart FormData-only credentials, and credentials added with http.request write/end need an explicit gateway address. Header-authenticated uploads stream normally. Recognized protected requests never fall back directly when rewriting fails; unrelated traffic is left alone. Auto-connect cannot protect an app that still uses a real provider key directly.
Verify the actual app
- Run
vallkey doctorin the project. Warnings are local readiness information, not proof of connection. - Run
vallkey verify, then restart or redeploy and make a safe request through your application's actual SDK/client. It shows each ghost key from this project's.envfiles as its request arrives. Use--jsonin CI; failures exit 1. - To check one exact request instead, take
x-guard-request-idfrom its response and runvallkey verify <key-id> --request-id <response-id>. It requires a request from the last five minutes with a successful settled response.--timeoutis 1–60 seconds here. - With a dedicated test key, call a harmless endpoint explicitly denied by its rules. Verify that response ID with
--expect denied. Never test using a destructive operation or rely on a paid call for setup verification.
Verification proves only that particular request. A cached success is reported as cached and does not prove a new provider call. Missing, stale, unsettled and provider-error responses do not pass. These commands require vallkey 0.8.0 or later. Update with npm install vallkey@latest, or run npx vallkey@latest connect.
Web pages and mobile apps (short-lived keys)
Keep the ghost key on your server, and give each signed-in user a short-lived key instead. It expires in minutes and can only do what the ghost key allows.
const { createSessionKey } = require('vallkey/session'); // reads VALLKEY_GHOST_KEY
const { session_key, expires_at } = await createSessionKey({ user: user.id, ttlSeconds: 900 });
// send session_key to the page or appOptions: user (your id for the person, for limits per user and blocking), ttlSeconds (60 to 86,400), timeoutMs (1 to 60,000; default 10,000), and optional allow and models to do less than the ghost key. Never call it from a web page. See https://vallkey.com/docs/browsers/.
AI coding agents (MCP)
vallkey mcp is an MCP server for Claude Code, Cursor, Windsurf and other agents. The agent never sees a real key: to protect one it names the .env file and variable, and the server reads the key, creates the ghost key and writes it back. Only the key id goes back to the agent.
npx vallkey login
claude mcp add vallkey -- npx -y vallkey mcpOther clients: { "mcpServers": { "vallkey": { "command": "npx", "args": ["-y", "vallkey", "mcp"] } } }
Tools: scan_project, protect_env_key, list_keys, get_key, get_activity (why a request was refused), list_providers, update_rules (looser rules still wait for the safety delay), list_real_keys, create_ghost_key (another ghost key for a shared real key, inside its outer rules) and kill_key.
CI
Set VALLKEY_TOKEN to an API token instead of signing in. To stop keys from being committed, on GitHub:
- uses: vallkeyhq/scan-action@v1Each key found is marked on its line in the pull request, masked. On other CI systems: npx --yes vallkey scan.
Where the sign-in is kept
~/.config/vallkey/config.json (on Windows %APPDATA%\vallkey\config.json), readable by you only. VALLKEY_CONFIG changes the path, and VALLKEY_API points the tool at another Vallkey server.
Docs: https://vallkey.com/docs/cli/
Development and security
See CONTRIBUTING.md, transport boundaries, and SECURITY.md. Saved management tokens are bound to the API origin used at sign-in. Switching VALLKEY_API requires signing in to that API or supplying its token explicitly with VALLKEY_TOKEN. Credential-bearing management and session requests do not follow redirects.
