Skip to content
Mastering Claude

Home / Security and data

Security and data8 minApplication

Reading is enough to expose a secret

A text search returns the contents of a secrets file it passes through, and a Read(./.env) deny rule does not apply to a shell command that reads files without ever naming that one.

A text search run on a whole folder returns every line that contains the pattern sought, preceded by the name of the file it comes from. A hidden .env file that contains this pattern comes up with the other results, without any read of that file having been requested.

What a Read(./.env) rule covers

A Read(./.env) deny rule, set in the permission settings, is meant to prevent Claude from reading this file. The Claude Code permissions documentation applies it to Claude's built-in file tools, to the shell file commands that Claude Code recognises, such as cat, head, tail, sed or tee, and to redirections: the target of an input redirection < file falls under the Read rules, that of an output redirection > file under the Edit rules. The same page then sets out two exclusions in so many words: a command that reads files without naming them, with the example of grep -r pattern . run from the folder that contains the file, and a subprocess that opens its own files, such as a Python or Node script.

Two search tools, two regimes

The word search covers two things. The shell command grep -r, which Claude runs in a terminal, falls outside the rule's scope, as the exclusion above says. Claude's built-in search tool, on the other hand, is a file tool: the documentation states that it applies the Read rules to the built-in tools that read files, such as Grep and Glob, on a best-effort basis, without listing the cases where this application would fail.

The demonstration

A throwaway folder holds a fake .env file, and a deny rule in the project settings file, .claude/settings.json.

mkdir -p demo-env && cd demo-env
mkdir -p .claude
printf '{"permissions":{"deny":["Read(./.env)"]}}\n' > .claude/settings.json
printf 'FAKE_KEY=example-not-a-real-key\n' > .env
grep -r KEY .
./.env:FAKE_KEY=example-not-a-real-key

Run in your own terminal, this search tests no rule: permission rules only apply to Claude's actions. It shows what the command brings up. The rule is tested by opening Claude Code in this folder and asking it to run the same search: according to the documented exclusion, the rule does not stop it, whereas a request to display the file with cat .env is refused according to the same page. A settings file accepted at startup does not say what the rule blocks: this trial does.

For a block imposed by the operating system on all processes, the documentation points to Claude Code's sandbox: an isolation that restricts shell commands' access to files and the network, child processes included. The Read deny rules are merged into its configuration. It runs on macOS, Linux and WSL2, not on native Windows. The lesson on what an agent can leak without being asked to shows where a read request that nobody typed can come from: an instruction hidden in content that Claude reads.

Figure 1

Does a Read(./.env) deny rule stop a search from revealing it

Réfuté
The rule stops Claude's file tools and the recognised shell commands that name the file, but it does not apply to a recursive search command that walks the folder without naming it.
Preuve
Claude Code permissions documentation, consulted on 2026-09-28: Read deny rules do not apply to a command that reads files without naming them, the example given being grep -r pattern . run from the folder that contains the file.
The verdict concerns the shell search command, Claude's built-in search tool falling under another regime.
Figure 2

What a Read(./.env) rule covers, according to the documentation

Access attempted by ClaudeCovered by the rule
Built-in read tool that opens .envYes
Recognised shell command that names the file, such as cat .envYes
Built-in search tool, such as GrepOn a best-effort basis, according to the documentation
grep -r command that does not name the fileNo, explicit exclusion
Python or Node script that opens its own filesNo, explicit exclusion
Five ways of reaching the same secrets file, and the scope the permissions documentation gives the rule for each.
Calibrate it yourself

An administrator adds a Read(./.env) deny rule to the .claude/settings.json file of her project, to protect the file that holds the login credentials. She opens Claude Code in this project and the session starts. The next day, she asks Claude to search, across the whole project folder, for every line that contains a given word, with a recursive shell search command.

Write in one sentence what this situation establishes, and in one sentence what it does not establish.

What to remember
  • A Read(./.env) rule stops Claude's file tools, the recognised shell commands that name the file and an input redirection that targets it.
  • A shell command that walks through a folder without naming the file, such as grep -r, falls outside the rule's documented scope.
  • Claude's built-in search tool receives the Read rules on a best-effort basis, which is checked by a trial on your own machine.
  • A search run in your own terminal shows what a command brings up, not what a Claude rule blocks.
  • The sandbox takes up the Read deny rules and has the operating system enforce them, child processes included, outside native Windows.
Do this now

Replay the demonstration in a new folder, then launch claude in that folder. First ask it to run grep -r KEY . and note whether the line of the fake .env shows up, then ask it to display .env with cat, then to search for KEY with its built-in search tool, and note for each request whether it goes through or is refused.

What still needs checking

These points depend on an interface or a rule that may have changed since this was written. Check them on your own screen before relying on them.

  • The documentation applies the Read rules to Claude's built-in search tool on a best-effort basis, without listing the failure cases: this lesson's exercise tests it on your machine, and that result is the one that holds for your version.
Check the source

Every datable claim in this lesson links here to the public text behind it. A source that does not open proves nothing.