Developers

Protect every API key from your terminal, your code and your CI

One command protects a whole project. Your SDKs keep working without a single code change. AI coding agents can set up keys without ever seeing one, and CI stops keys from being committed.

Command line

View
npx vallkey init

Python

View
pip install vallkey

GitHub Actions

View
uses: vallkeyhq/scan-action@v1

Open source under the MIT license, with no dependencies. Node.js 18 or newer, Python 3.8 or newer.

The command line

From a .env file full of keys to ghost keys, in a minute

Sign in once from your browser. Then init finds the keys in your .env files, creates ghost keys with each provider's safe default rules, and writes them back. Your real keys are stored encrypted and leave the files.

login
Approve this computer in your browser, once. The tool gets its own API token, which you can revoke in Settings.
init
Find the API keys in your .env files, create a ghost key for each and write the ghost keys back.
scan
Look for API keys in your code and your whole git history. Keys are always masked. Exits with 1 for CI.
keys
List your ghost keys.
kill <key id>
Stop a ghost key everywhere, right away.
mcp
Run the MCP server for AI coding agents.
Terminal
$ npx vallkey login  Your code: BCDF-GHJK   (approve it in your browser)✓ Signed in. $ npx vallkey initThese keys can become ghost keys:  .env  OPENAI_API_KEY     OpenAI API key     sk-proj-…(52 chars)  .env  STRIPE_SECRET_KEY  Stripe secret key  sk_live_…(40 chars) ✓ Swapped 2 keys for ghost keys.Next:  • The official SDKs read OPENAI_BASE_URL, so no code change.  • Stripe: start your app with node -r vallkey/auto $ npx vallkey scan --history✓ No API keys found in 312 files or in git history.

Any SDK, no code changes

Your code stays exactly as it is

Load Vallkey's small helper once. Every request that carries a ghost key goes to Vallkey with the same path; every other request is left alone. No base URLs to set, in any library.

Node.js

Terminal
$ npm install vallkey$ node -r vallkey/auto server.js # Or for next dev, vite and other tools:$ NODE_OPTIONS='-r vallkey/auto' npm run dev
fetchhttp and httpsOpenAIAnthropicStripeGoogle Gen AIaxiosgotws

Python

Terminal
$ pip install vallkey$ VALLKEY_AUTO=1 python app.py # Or in code, anywhere:import vallkey.auto
httpxhttpx2requestsaiohttpurllibOpenAIAnthropicStripe

It looks for a ghost key

In the headers, in Basic credentials and in the query string of each request your app sends.

It sends that request to Vallkey

Same path, same body. Vallkey checks the rules, swaps in the real key and forwards it.

It leaves the rest alone

Requests without a ghost key go out exactly as before. Turn it off with VALLKEY_AUTO=0.

For web pages and mobile apps

Call APIs from the browser, with nothing in it worth stealing

Your server makes a short-lived key for each signed-in user, and the page or app uses that one. It expires in minutes, can only do what its ghost key allows, and stops the moment you kill or rotate the ghost key.

  • Only your server can make them: requests from a web page are refused
  • Limits per user, including a daily AI budget, across all of a user's keys
  • Block one person in a click, without touching anyone else
  • List the websites allowed to use a key; pages elsewhere are refused
Read the guide
Your server (Node.js)
import { createSessionKey } from 'vallkey/session' // after your own sign-in checkconst { session_key } = await createSessionKey({ user: user.id })
Your server (Python)
from vallkey.session import create_session_keysession_key = create_session_key(user=user.id)["session_key"]
Your web page or app
const openai = new OpenAI({  apiKey: session_key,  baseURL: 'https://api.vallkey.com/v1',  dangerouslyAllowBrowser: true,})

For AI coding agents

Let your agent set up keys, without ever seeing one

The Vallkey MCP server works with Claude Code, Cursor, Windsurf and any other MCP client. To protect a key, the agent names the variable; the server on your computer reads the key, creates the ghost key and writes it back. Only the key id reaches the agent.

  • Your MCP client asks you before each tool runs
  • Files outside the project folder are refused
  • Looser rules still wait for the safety delay
  • Every action is in your audit log, marked as an agent's
Claude Code
$ npx vallkey login$ claude mcp add vallkey -- npx -y vallkey mcp
Cursor, Windsurf and other clients
{  "mcpServers": {    "vallkey": { "command": "npx", "args": ["-y", "vallkey", "mcp"] }  }}
scan_projectFinds API keys in the project, masked.
protect_env_keySwaps a key in a .env file for a ghost key.
list_keys, get_keyLists keys and shows one key's rules and status.
get_activityRecent requests, with the reason for each refused one.
update_rulesChanges some rules. Looser ones still wait for the safety delay.
kill_keyStops a key at once. Reviving it is left to a person.

In CI

A committed key fails the build, on the right line

The GitHub Action scans every push and pull request. Each key it finds is marked on its line and listed in the run summary, always masked. Scan the whole history too, or only report without failing.

.github/workflows/keys.yml
on: [push, pull_request]jobs:  scan:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7      - uses: vallkeyhq/scan-action@v1

On other CI systems: npx --yes vallkey scan

Add checkout#1281 check failed
src/pay.ts
11+ const stripe = new Stripe("sk_live_51Mx9…")

Stripe secret key found

Stripe secret key sk_live_…(40 chars). Treat it as leaked: create a new key at the provider, revoke this one, and keep keys out of the code.

Management API

Everything the dashboard does, by API

Create keys, change rules, read activity and kill keys from your own scripts. Each script gets its own API token, read only or admin, that you can revoke at any time.

Create a ghost key
1curl https://api.vallkey.com/_guard/v1/keys \2  -H "Authorization: Bearer $VALLKEY_TOKEN" \3  -H "Content-Type: application/json" \4  -d '{"provider": "openai", "real_key": "sk-...", "label": "Support bot",5       "rules": {"allowedModels": ["gpt-5-mini"], "dailyTokens": 2000000}}'

Write-only real keys

A real key goes in once and never comes back out, from the API or anywhere else.

Same errors as Stripe and OpenAI

Refusals use their error shape, so their SDKs show our messages as they are.

Protect your keys before the next commit

Free plan, no card needed. npx vallkey init takes about a minute.