The House That Watches: When Your AI Agent's Home Leaks Your Secrets
On the gap between agent promises and system reality
You train your dog not to eat from the table. The dog obeys. Then the table tilts, and the food falls on the floor.
Was it the dog's fault?
The Story
We work with AI agents every day. We build with them, we trust them with our code, and we set rules — clear rules — about what they can and cannot see.
One of those rules: never read the file that holds our passwords and API keys. The agent respected this rule for two weeks. We tested it. It refused every time, politely, even when asked directly.
Then, on a Tuesday morning, we edited that passwords file. Added one line. Saved it.
And the system — not the agent, the system it lives inside — sent the entire file contents into the conversation. Every password. Every key. Ten secrets exposed in one keystroke.
The agent didn't break its promise. The house it lives in opened the door while nobody was looking.
For Everyone — What This Means
Imagine you hire a locksmith. You tell him: "You can fix any door in the house, but never open the safe." The locksmith agrees. He is trustworthy. He never touches the safe.
But the house has security cameras. And the cameras film everything — including the safe's combination when you open it. The footage goes to a monitoring room where the locksmith happens to be sitting.
He didn't look at the safe. The camera showed it to him.
This is what happened with AI coding assistants. The assistant follows the rules. But the software it runs inside — the code editor, the file-watching system, the IDE — does not know which files are secret. It watches everything. When a secret file changes, it sends the contents to the assistant automatically.
The assistant never asked. The system volunteered.
What was exposed?
Keys that connect to paid services — like an access card to a building. Anyone who has the key can enter, use the service, and charge the account. We had to change every lock immediately. Ten keys rotated in one afternoon.
Could this happen to you?
If you use an AI coding assistant (Claude Code, Cursor, GitHub Copilot, Windsurf, or any similar tool) and you have a .env file with passwords or API keys in your project — yes. The same mechanism exists in most of these tools.
What should you do?
Never edit your passwords file while the AI assistant is running. Close it first, edit, then reopen. This is the only reliable protection today.
For the Curious — How It Works
AI coding assistants connect to your code editor (VSCode, JetBrains, etc.) through a file-watching system. When you modify a file, the editor sends a notification: "This file changed. Here are the new contents." The assistant uses this to stay in sync with your work.
The problem: the file-watcher does not distinguish between source code and secrets. A Python file and a .env file look the same to the watcher — they are both text files that changed.
Developers know to add .env to .gitignore — this prevents secrets from being committed to version control. But .gitignore is a git concept. It tells git what to skip. It does not tell the file-watcher, the IDE, or the AI assistant's context system.
The chain of failure:
- You edit
.envin the editor - The editor detects the change and sends the full contents to the AI system
- The AI system injects it into the conversation as a "system reminder"
- The agent sees everything — despite having a rule not to read that file
- The conversation is logged — the secrets are now in the session history
The agent's rule says: "Don't use the Read tool on .env." But the system reminder is not a tool the agent invoked. It is infrastructure — like the security camera that films the safe.
The deny rules
You can configure deny rules in the AI assistant's settings:
{
"permissions": {
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(.streamlit/secrets.toml)"
]
}
}
These block the agent from actively reading secrets. But they do not block the system from passively sending them through file-watcher notifications.
Two layers protected. Two layers exposed.
For the Expert — Architecture and Prior Art
The four-layer model
Layer 1 — Agent rules "Don't read .env" ✅ Respected
Layer 2 — Tool permissions Read tool blocked ✅ Enforced
Layer 3 — System events File-watcher notifies ❌ No filter
Layer 4 — IDE integration VSCode sends changes ❌ No exclude list
The permissions.deny configuration in Claude Code's settings.json governs layers 1-2. Layers 3-4 operate independently and have no equivalent deny mechanism as of March 2026.
Three bypass vectors, one root cause
The deny rules are bypassed through:
-
<system-reminder>on file modification — the IDE notifies Claude Code of changes to any watched file, including.env. The notification includes full file contents. This is the vector we hit. -
Open-tab context injection — when
.envis open in a VSCode tab, the IDE extension sends its contents as contextual information. Issue #30708 documents this. -
Indexing — Claude Code's file indexing may process
.envcontents regardless of.claudeignoreor deny rules. Issue #37170 confirms.claudeignorebypasses.
Root cause: separation of concerns violation. The permission system governs the agent's tool calls but not the platform's system events. The same file content flows through three independent channels (tools, watcher, indexer), and only one channel respects the deny configuration.
Prior art
This is a known class of vulnerability across AI coding assistants:
- Knostic.ai documented automatic .env loading without consent and cross-platform leakage across Claude Code, Cursor, and Windsurf
- The Register covered the story in January 2026
- CVE-2025-59536 (CVSS 8.7) — RCE and API key exfiltration through Claude Code project files; CVE-2026-21852 (CVSS 5.3) — information disclosure in project-load flow (Check Point Research)
- GitGuardian 2025 — AI-assisted commits show 2x the secret incidence rate (3.2% vs 1.5%)
GitHub issues on anthropics/claude-code:
- #4282 — system reminders bypass deny settings (our exact vector)
- #9637 — aggressive secrets reading from
.env - #7921 — unauthorized
.envfile access - #30708 — request for file exclusion in open-file context
- #25053 — mark sensitive env vars to prevent exposure
What the correct fix looks like
The file-watcher notification system needs a segmented exclude list — ideally inheriting from .gitignore patterns by default, with an explicit override in settings.json:
{
"fileWatcher": {
"exclude": [
".env",
".env.*",
"**/*.key",
"**/*.pem",
"**/secrets.toml",
"**/credentials*"
]
}
}
This configuration does not exist as of March 2026. The feature request is #30708.
In the meantime, a practical alternative exists: Cloak (MIT, v0.1.0) encrypts secrets on disk with AES-256-GCM, replacing them with structurally valid sandbox values. The file-watcher still fires — but it volunteers harmless fakes. The real secrets decrypt only in your editor's memory, gated by OS keychain. It solves the problem at the filesystem level rather than waiting for the platform to fix itself.
Runtime vs. file-level secrets
An important distinction: deny rules block agent access to secret files, not to runtime environment variables. Scripts that use $DISCORD_WEBHOOK from the shell environment still work — they read from memory, not from disk. The agent cannot source .env, but a script launched by the user can. This is the correct separation:
Agent reads .env file → BLOCKED (deny rule)
Script reads $ENV_VAR → WORKS (shell environment, not file)
System-reminder shows .env → EXPOSED (no deny at this layer)
Mitigation stack (defense in depth)
| Layer | Protection | Status |
|---|---|---|
| Agent rules (memory) | "Never read .env" | ✅ Active |
permissions.deny | Block Read/Bash on .env patterns | ✅ Configured |
.claudeignore | Exclude from indexing | ⚠️ Partially effective |
| Operational discipline | Close .env tab before agent session | ✅ Human gate |
| File-watcher exclude | System-level pattern exclusion | ❌ Does not exist yet |
| Filesystem encryption | Encrypt secrets on disk, decrypt in-memory in editor only | ✅ Cloak (MIT, v0.1.0) |
| Secrets manager | Move secrets out of .env entirely | 🔄 Migration path |
The Principle
Sovereignty is not only about where your data is hosted. It is about who — and what — can see it at rest, in transit, and in the moments between keystrokes.
The agent did not betray us. The system that carries the agent did not know it was carrying secrets. The gap is not malice. It is architecture. And architecture can be fixed — once it is named.
We named it. We rotated every key. We documented the incident. And we published this — not to shame a tool we use every day, but because the gap between what an AI promises and what its platform delivers is something every builder needs to understand.
You can train the dog perfectly. But if the table is not level, the food will fall.
Fix the table.
Related: The Þorn in the Þread | The Keys to the House
