All posts 🛡️

How to Protect Your API Keys From AI Coding Agents

We asked Claude Code to debug a failing Stripe integration. It printed the full HTTP request — headers included. Our live API key, right there in the conversation log. Stored on Anthropic's servers. Visible in terminal scrollback. Gone.

The agent wasn't being malicious. It was doing exactly what we asked. Our .env file was just sitting there in the project directory, and to Claude Code, it's just another file.

We've since documented six specific ways this happens. But documenting the problem wasn't enough. We needed to actually fix it. Here are five strategies that work — ranked from simplest to most paranoid.

First, understand the blast radius

Claude Code, Cursor, Copilot, Codex — they all have file system access. They need it to be useful. They read your source code, your config, your project structure. And your .env file sits right there alongside everything else.

Once an agent reads a secret, it can end up in:

None of this is the agent's fault. Your credentials are in the blast radius because you put them in a plaintext file with zero access control.

1. Get secrets off disk

The simplest fix is the best one. No file, no leak.

.env files are plaintext — no encryption, no auth, readable by any process running as your user. Move your secrets to your OS credential store instead. On macOS, that's the Keychain: hardware-encrypted, Touch ID protected, and — crucially — not a file sitting in your project directory.

# The old way: plaintext file any process can read
cat .env
STRIPE_KEY=sk_live_51Hx...

# The new way: import to Keychain, delete the file
# Drag the .env onto the NoxKey menu bar icon — or
# from an agent, scan then import under one Touch ID:
#   noxkey_scan(path: ".", suggested_org: "myorg",
#               suggested_project: "general")
#   noxkey_admin(action: "import", entries: [...])
rm .env

# Load when you need it (agent calls the MCP tool):
#   noxkey_get(account: "myorg/general/STRIPE_KEY")
# → returns: source '/tmp/noxkey_xxx.sh'
# Run that line in Bash → $STRIPE_KEY in env, no file on disk

This alone eliminates the most common leak vector. Everything else is defense in depth.

2. Inject at runtime, not from files

The dotenv pattern reads a file at startup. That file exists on disk for your entire development session. Runtime injection is different — secrets flow from the credential store directly into your process environment, on demand.

# dotenv: secret lives on disk, readable by anything
require('dotenv').config()

# Runtime injection via MCP: secret lives in memory only
#   noxkey_get(account: "myorg/general/STRIPE_KEY")
# → run the returned source line in Bash
node app.js
# process.env.STRIPE_KEY works, but no file exists

When you need multiple secrets, asking for a prefix cuts the friction:

# One Touch ID, every key under the prefix loaded into your shell
#   noxkey_get(account: "myorg/general")
# → run the returned source line in Bash
# $STRIPE_KEY, $DATABASE_URL, $OPENAI_API_KEY are now in the environment
# Subsequent get calls under myorg are cached for the session window

The secret exists only in your shell's memory. When the session ends, it's gone.

3. Detect the agent, change the delivery

Here's a question most credential managers don't ask: is a human requesting this secret, or is an AI agent?

It matters. When you click "Copy" in the menu bar app, you want the value on your clipboard. When Claude Code calls noxkey_get through MCP, the value should never enter the conversation.

NoxKey treats the agent as a first-class caller. The bundled MCP server is the path agents use — noxkey_get always returns a self-deleting source command, never a raw value. For shell processes that aren't going through MCP, process-tree detection picks up the slack: every process has a parent, walk up the tree, and you can see who's really asking.

Terminal → zsh → claude → bash -c → noxkey
                  ↑
          agent detected here

Either way, when NoxKey is talking to an agent it switches behavior automatically:

The agent can use the secret — it's in process.env. It just never sees it.

4. Make leaked keys expire fast

Long-lived API keys are risky with or without AI agents. But agents make it worse. If a leaked key expires in 15 minutes, the damage window is tiny. If it's been valid for two years, the damage window is the rest of its life.

Where your services support it, prefer short-lived credentials:

For keys that can't expire, establish a rotation habit. One update in your credential store beats finding-and-replacing across six .env files scattered across your machine.

All four together

Each strategy covers a different leak vector:

Leak vectorStrategy
Agent reads .env fileGet secrets off disk
Secret persists on diskRuntime injection
Agent accesses credential storeProcess-tree detection
Leaked key stays validShort-lived tokens

We built NoxKey because we needed all four in one tool. We were using Claude Code every day and kept finding our own API keys in places they shouldn't be. Three steps and it's done:

# 1. Install NoxKey from the Mac App Store
# 2. Drag your .env onto the menu bar icon → review sheet
#    → Touch ID once → all keys imported
# 3. Delete the .env, flip Agent Guard on in Settings
rm .env

Frequently asked questions

Can Claude Code actually read my .env files?
Yes. Claude Code has full file system access and reads project files to understand context. Your .env is just another file in the project directory. There's no access control preventing it. The fix is to not have a .env file.
Does Cursor index my API keys?
Cursor indexes your workspace for context-aware suggestions. If your workspace contains a .env file, those values are part of the index. Moving secrets to the Keychain means there's nothing to index.
How does process-tree detection actually work?
When a process requests a secret, NoxKey walks the process hierarchy upward — child to parent to grandparent — looking for known AI agent processes. If one is found, the secret is delivered via encrypted handoff instead of as a raw value. Full technical deep-dive here.
Can the AI agent still use my API key for testing?
Yes. The agent calls the noxkey_get MCP tool, runs the returned source line in Bash, and the secret loads into process.env via the encrypted handoff. The agent can run tests, make API calls, and debug integrations — it just can't see the raw value. It writes process.env.STRIPE_KEY in code because that's the only interface it knows.
Is this macOS only?
NoxKey is macOS only (built on the Keychain and Secure Enclave). But the strategies are universal — on Linux use the system keyring or pass, on Windows use the Credential Manager. The principle is the same: secrets off disk, into the OS credential store.

Download on the Mac App Store

Free. No account. No cloud. Your secrets stay on your machine.