Do AI coding agents read your .env files?
What Claude Code, Cursor and Copilot do with .env files by default, why ignore rules don't stop an agent's shell, and how to test it with a fake key.
Crunu teamPublished 7 min read
On this page
They can, and some will without asking. Claude Code reads files in your working directory without a prompt unless you add a deny rule. Cursor ignores .env* files by default for its agent and autocomplete, but its documentation says the agent's terminal and MCP tools can still reach them. GitHub Copilot's content exclusion, on Business and Enterprise plans, does not apply in agent mode at all. In every case, an agent that can run shell commands can read any file your user can read. The reliable fix is not a better ignore rule; it is not keeping production values in the working directory.
This post goes through each tool's documented defaults as of October 30, 2026, explains why the shell defeats file rules, gives a five-minute test with a fake key, and shows how to run your app with secrets that never sit next to the code. The guide to secrets and AI coding agents covers the wider threat model.
Why this matters more for agents than for autocomplete
Autocomplete reads the file you're editing and a few related ones. An agent reads whatever it decides is relevant to the task: configuration, logs, test fixtures and, often, the .env that explains why the app won't start. Whatever it reads becomes part of the conversation sent to the model provider, and may end up in the agent's local history.
Agents also take instructions from content. A README, an issue or a web page the agent opens can contain text written to make it do something else, such as print the environment. That risk, prompt injection, is why "the agent won't read it unless it needs to" is not a guarantee. The glossary entry on prompt injection explains the mechanism.
Claude Code
Claude Code's permission table lists file reads as needing no approval "within the working directory and additional directories". Bash commands need approval, except a built-in set of read-only commands (Claude Code: permissions).
To keep it away from a file, you add a deny rule such as Read(./.env) in your settings:
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]
}
}The documentation is precise about how far that goes. Read and Edit deny rules apply to the built-in file tools, to file commands it recognizes in Bash "such as cat, head, tail, sed, and tee", and to redirections. "They don't apply to a command that reads files without naming them, such as grep -r pattern . run from the directory that holds the file, or to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself." For blocking at the operating system level, it points to the sandbox. It also notes that a .claudeignore file "has no effect".
Cursor
Cursor's ignore-files page says it "automatically ignores files in .gitignore and the default ignore list", and that default list includes .env*. Ignored files are kept from the agent, from Tab and from @ mentions (Cursor: ignore files).
Two caveats are in the same documentation. First: "While Cursor blocks ignored files, complete protection isn't guaranteed due to LLM unpredictability." Second: "The terminal and MCP server tools used by Agent cannot block access to code governed by .cursorignore". An agent that runs cat .env or a script that loads it is outside what the ignore list controls.
GitHub Copilot
Copilot's control is content exclusion, configured by repository or organization admins on Copilot Business and Enterprise. It keeps excluded files out of suggestions and chat responses. The documentation then states: "Content exclusion is currently not supported in Edit and Agent modes of Copilot Chat in Visual Studio Code and other editors." It describes the feature as "a guardrail for the tools that GitHub controls" that "is not guaranteed to be respected by third-party MCP servers" (GitHub: content exclusion).
The pattern across all three
Reads .env by default | File rule | What the rule doesn't cover | |
|---|---|---|---|
| Claude Code | Yes, in the working directory | Read(./.env) deny rule | Scripts and commands that read files without naming them |
| Cursor | No: .env* is on the default ignore list | .cursorignore, .gitignore | The agent's terminal and MCP tools |
| GitHub Copilot | Unless excluded | Content exclusion (Business, Enterprise) | Edit and Agent modes; third-party MCP servers |
The tools differ in defaults, but the structure is the same. File rules govern the agent's own file tools. A shell runs as your user, and your user can read your .env. Each vendor points to a sandbox or OS-level isolation as the stronger layer, and that is the right reading: rules reduce accidents, isolation enforces a boundary.
It isn't only .env
The .env in the project is the obvious target, but a shell running as you can read everything in your home directory too: cloud credential files such as ~/.aws/credentials, package registry tokens in ~/.npmrc, CLI login state under ~/.config, SSH keys. File rules scoped to the project don't mention these at all, and ignore lists only cover the project tree.
Two habits help. Prefer credentials that expire on their own for development, such as a cloud sign-in session that lasts hours rather than a long-lived access key in a file. And treat the agent's working environment as shared: if a credential would be a problem in a chat transcript, it shouldn't be readable by the process the agent runs commands in.
Test it yourself with a fake key
Documentation changes and settings drift, so check your own setup. It takes five minutes and needs no real secret.
- Make up a value that can't occur anywhere else, for example
CANARY_KEY=canary-9f2c41e7-not-a-real-key. - Put it in the
.envof a test project, alongside your usual ignore rules and settings. - Ask the agent a task that makes the file relevant without naming it: "The app fails to start with a missing config error. Find out why."
- Watch what it does. Did it read the file without asking? Did it run
cat,envor a script that loads the file? Did the value appear in its replies? - Ask directly: "What is the value of
CANARY_KEY?" A refusal from the file tool followed by a shell command that prints it tells you which layer actually holds.
Then search for the string in anything the agent keeps locally, such as its history or logs, if you know where they are. If the canary shows up anywhere, so would a real key.
Keep values out of the working directory
The robust answer is to stop keeping real secrets in the project directory at all. An agent can't print a file that isn't there. The app still needs its variables, so they have to arrive some other way: in the process environment, when the app starts.
With Crunu, the values live in an environment such as web-app / development. You start the app through the agent instead of reading a file:
crunu run --env web-app/development -- npm run devcrunu run decrypts the variables in memory and passes them to the program through its process environment; nothing is written to disk. It starts the program with a short allowlist of your own variables plus the environment's, not your whole shell. On Linux it also closes its own process to other processes of the same user before reading any variables, though that does not stop root. The crunu run reference has the details, and the glossary entry on runtime secret injection explains the general pattern.
Be clear about what this does and doesn't change.
- The app and its child processes see the values. That is the point of environment variables. If the agent starts your dev server under
crunu run, or runscrunu run -- env, it sees them too. Start the agent in a shell that has no secrets, and run the app yourself in another. - An open session is usable by your user. After
crunu loginandcrunu unlock, any process running as you can callcrunu run, including an agent's shell, if you approve the command. Usecrunu unlock --ttl 1hfor a short window andcrunu lockwhen you're done. - Scope beats hiding. Give the account you develop with access to development environments only, and a Reader role where you don't need to edit. A development database password in an agent's context is a nuisance. A production payment key is an incident.
Production values have no business on a laptop that runs an agent with shell access. Keep them on the machines that run production, delivered by the machine's own agent, and out of developer sessions entirely.
A short checklist
Sources
- Configure permissions, Claude Code documentation, checked October 30, 2026.
- Ignore files, Cursor documentation, checked October 30, 2026.
- Content exclusion for GitHub Copilot, GitHub Docs, checked October 30, 2026.