Secret isolation for AI coding agents.
Agents use your secrets but never see them.
What It Does · Install · Quick Start · How It Works · Security Modes · Configuration · CLI Reference · Comparison
blindenv lets AI agents use your API keys, database credentials, and tokens — without ever seeing them.
- Secret injection — Resolves
$VARreferences in an isolated subprocess. The agent writes$API_KEY, the real value is injected behind the scenes. - Output redaction — Scans all stdout/stderr and replaces secret values with
[BLINDED]before the agent sees it. - File invisibility — Secret files return "does not exist" for reads/edits and are silently excluded from searches and listings. The agent doesn't know they're there.
- Config protection — Agents cannot modify
blindenv.yml. The rules are tamper-proof. - Content-aware blocking — Even if a secret file is copied or renamed, any file containing a secret value is blocked. Path evasion doesn't work.
Agent writes: curl -H "Authorization: $API_KEY" https://api.example.com
↓
blindenv proxy: Injects real value into subprocess env
↓
Agent receives: {"result": "ok", "token": "[BLINDED]"}
No matter what the agent tries, it cannot see your secrets:
| Agent attempts | What the agent sees |
|---|---|
Read .env with Read tool |
File does not exist |
Edit or Write to .env |
File does not exist |
grep API_KEY .env |
No results (secret files silently excluded) |
Glob **/.env* to discover files |
No results (secret files silently excluded) |
cat .env in Bash |
Secret file inaccessible in subprocess |
Copy .env to tmp.txt, read the copy |
File does not exist (content-aware scan) |
echo $API_KEY to print the value |
[BLINDED] |
Edit blindenv.yml to disable rules |
Blocked — config is tamper-proof |
The agent can't read, find, search, edit, or write secret files — because as far as it knows, they don't exist. Meanwhile, API calls work, deploys succeed, and services respond. The agent gets full functionality without ever seeing the credentials that make it happen.
/plugin marketplace add neuradex/blindenv
/plugin install blindenv@blindenvThat's it. On the next session start, the binary is automatically downloaded from GitHub Releases for your platform and blindenv.yml is auto-generated in your project root.
Open blindenv.yml and configure which files contain secrets:
secret_files:
- .env
- .env.local
# - ~/.aws/credentialsOnce configured, the agent cannot even know these files exist — all access is structurally blocked.
git clone https://github.com/neuradex/blindenv.git
cd blindenv
make build # → ./blindenvOr install globally: go install github.com/neuradex/blindenv@latest
See CONTRIBUTING.md for development setup and project structure.
| Platform | Architecture | |
|---|---|---|
| macOS | Apple Silicon (arm64) | Supported |
| macOS | Intel (amd64) | Supported |
| Linux | x86_64 (amd64) | Supported |
| Linux | ARM (arm64) | Supported |
| Windows | x86_64 (amd64) | Supported |
| Windows | ARM64 | Supported |
With blindenv.yml in place, all key-value pairs in your .env files are automatically:
| What happens | |
|---|---|
| Injected | Secret values available as $VAR in commands via blindenv run |
| Redacted | Any output containing a secret value → [BLINDED] |
| Blocked | Agent cannot Read, Grep, Edit, or Write secret files |
# Your .env contains: API_KEY=sk-a1b2c3d4
blindenv run 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com'
# → {"result": "ok", "key": "[BLINDED]"}When used as a Claude Code plugin, you don't even need blindenv run — the hook rewrites Bash commands automatically.
| # | Layer | What it does |
|---|---|---|
| 1 | Subprocess isolation | Secrets exist only in the subprocess environment — never in the agent's context |
| 2 | Output redaction | stdout/stderr scanned for secret values, replaced with [BLINDED] |
| 3 | File invisibility | Secret files return "does not exist" for Read/Edit/Write and are silently excluded from Grep/Glob |
| 4 | Config protection | Agent cannot modify blindenv.yml — the rules are tamper-proof |
| 5 | Content-aware blocking | Files containing secret values are blocked regardless of path — copying or renaming won't help |
With the plugin installed, six PreToolUse hooks guard every agent action:
| Tool | Hook | Behavior |
|---|---|---|
| Bash | blindenv hook cc bash |
Rewrites command to blindenv run '...' — secrets injected, output redacted |
| Read | blindenv hook cc read |
Secret files → "does not exist" (no blindenv fingerprint) |
| Grep | blindenv hook cc grep |
Injects exclusion globs — secret files silently omitted from results |
| Glob | blindenv hook cc glob |
Injects exclusion patterns — secret files silently omitted from listings |
| Edit | blindenv hook cc guard-file |
Secret files → "does not exist"; blindenv.yml → explicit block |
| Write | blindenv hook cc guard-file |
Secret files → "does not exist"; blindenv.yml → explicit block |
The agent never sees a "blocked" message for secret files — they simply don't exist. The only explicit block is on blindenv.yml itself, and only because the agent already knows blindenv is installed.
"Not knowing something exists is the ultimate security."
blindenv offers three security modes. Choose how much the agent should see:
# blindenv.yml
mode: block # blind (default) | block | stash| Mode | Secret file access | Secret values | ls reveals files? |
|---|---|---|---|
blind (default) |
Readable | [BLINDED] |
Yes |
block |
Explicit deny | Hidden | Yes |
stash |
File not found | Hidden | No (physically removed) |
The agent can read secret files, but all secret values are replaced with [BLINDED]. Variable names, comments, and file structure remain visible. The most natural experience — no mystery, no blocked messages, the agent just can't see what matters.
# Agent reads .env:
API_KEY=[BLINDED]
DB_PASSWORD=[BLINDED]
DEBUG=true ← non-secret values pass through
The agent sees "access denied" when it tries to read secret files. It knows the files exist but cannot access them. Use this when you want clear feedback about what's protected.
The strongest mode. At session start, secret files are moved to a secure cache (~/.cache/blindenv/) and physically deleted from disk. Even ls, find, and tree in Bash reveal nothing. The files genuinely don't exist during the session.
Secrets remain fully functional — they're served from cache for injection and output blinding. Use blindenv cache-restore to bring them back after the session.
# blindenv.yml
mode: block # blind (default) | block | stash
secret_files: # .env files — auto-parsed, paths blocked from agent
- .env
- .env.local
- ~/.aws/credentials
inject: # env vars from host process — injected + redacted
- CI_TOKEN
- DEPLOY_KEY
passthrough: # non-secret vars — explicit allowlist (strict mode)
- PATH
- HOME
- LANG| Field | Purpose | When to use |
|---|---|---|
mode |
Security mode: blind, block, or stash |
When you want block/stash instead of the default blind |
secret_files |
Parse .env files, inject values, block file access |
Always — this is the primary mechanism |
inject |
Pull env vars from the host process | CI/CD secrets, vars not in any file |
passthrough |
Strict allowlist for non-secret vars | High-security environments |
secret_files alone is usually enough. inject is for env vars that exist in the host process but not in any file (e.g. CI secrets).
When passthrough is set, the subprocess gets ONLY those vars plus injected secrets (strict mode). Without it, the full host env is inherited (permissive mode).
Config is discovered by walking up from cwd to /, then checking ~/.blindenv.yml. The nearest one wins — just like .gitignore.
blindenv run '<command>' Execute with secret isolation + output redaction
blindenv check-file <path> Check if file is blocked (exit 2 = blocked)
blindenv has-config Exit 0 if config with secrets exists, 1 otherwise
blindenv stash Move secret files to cache, delete originals (stash mode only)
blindenv cache-restore Restore secret files from cache
blindenv cache-refresh Re-cache secret files (after you edit .env)
blindenv hook cc <hook> Claude Code PreToolUse hooks
bash | read | grep | glob | guard-file
Traditional secret managers solve storage and delivery — where secrets live and how they reach your process. blindenv solves a different problem: what happens after delivery, when an AI agent is the one running the process.
| Capability | Secret managers | blindenv |
|---|---|---|
| Centralized secret storage | Yes | — (uses your existing .env) |
| Runtime injection into processes | Yes | Yes |
| Output redaction | — | Yes |
| File invisibility (not blocked — invisible) | — | Yes |
| Content-aware blocking | — | Yes |
| Config tamper-proofing | — | Yes |
| AI agent tool hooks | — | Yes |
Secret managers and blindenv are complementary. A secret manager gets the right values into your .env or CI pipeline. blindenv makes sure the agent that runs your commands can use those values without seeing them.
Without an agent-aware layer, an injected secret can still be read from files, echoed to stdout, or leaked through copied files — regardless of how well it was managed upstream.
Your AI agent needs your API key. So you paste it into the chat. Or you put it in .env and let the agent read it.
Either way, the secret is now in the agent's context — one prompt injection away from leaking. The agent doesn't need to be malicious. It just needs to be tricked.
"But I opted out of training." — Maybe. Your provider may not use your data for training, and may delete it after the retention period as promised. But between the moment your secret hits their server and the moment it's deleted, anything can happen. A breach, a subpoena, an internal incident, a misconfigured backup. You don't control that timeline.
And unlike other services, what's stored here isn't just a password in isolation — it's your credential with full context. The conversation contains what the key is for, which service it accesses, how the API is called, what infrastructure it connects to. If that record is ever compromised, it's not just a leaked key. It's a complete playbook for exploitation.
The only real defense is to never send the secret in the first place.
"Just don't give agents API keys." — Sure. And don't give your car keys to the valet. Park three blocks away, carry your luggage in the rain, and congratulate yourself on your security posture. The point of an AI agent is to do real work — deploy code, call APIs, access services. An agent without credentials is a very expensive autocomplete. The goal isn't to stop using keys. It's to use them safely.
blindenv solves this structurally. Not through prompts. Not through trust. Through isolation.
MIT
Your agent doesn't need your keys. It needs what your keys unlock.
blindenv gives it access without exposure.