Lock down the files your AI can read

Even in Manual mode, your AI agent can read your .env unasked. 15 minutes to lock away your keys, in the app and the terminal, and what still gets through.

Translucent blue glass terminal window where the command cat .env gets the answer Permission denied, in gold
Series · episode 1 of 6AI Agents Under Control Contents
  1. Prologue Your AI agent has the keys to your house
  2. 1 Lock down the files your AI can readyou are here
  3. 2 Guardrails that say no to your AI agent Coming up
  4. 3 Your secrets have no business in your AI Coming up
  5. 4 Your AI agent only leaves through the planned door Coming up
  6. 5 Your MCP, write it yourself with your AI Coming up
  7. 6 Watch your AI agent like an employee Coming up
See the series page →

Episode 1 of the “AI agents under control” series. Beginner level. You need Claude Code, in the Claude app or in the terminal, and episode 0 in mind. Tested on Claude Code 2.1.299 and 2.1.309, October 19 and 23, 2026.

Screenshots taken on a French-language Mac, the agent answers in the language you write to it.

On October 16, I set a trap for Claude Code. A test repository, a hidden instruction in the README, and a fake key in a .env file.

In auto mode, the default starting mode, the model sniffed out the instruction and refused to send the key.

In Manual mode, the one you pick to stay in control, it opened the .env without asking anything. Then it copied the key into its answer, and so into the history kept on disk.

Third run, in auto mode, with the settings of my everyday machine, locked down for a long time. The read was stopped dead by a hook, a guardrail I cover in the next episode of the series.

This episode gives you the layer underneath, the one that fits in a plain text file.

Read, Your AI agent has the keys to your house


Manual doesn’t mean “asks before reading”

Manual mode has three names. default in the settings file, “manual mode” in the terminal, “Manual” in the Claude app. Here, it will be Manual.

It asks before editing a file or running most commands. Not before reading. Nor before commands that only read, like grep.

There’s one limit. These free reads stay inside the working directory, the one you launched Claude Code from, and inside the folders you added to it. Outside of it, it asks. Anthropic says so, in a table neatly tucked away at the bottom of another page.

My test .env was in the working directory. It was read, perfectly legally.

In auto mode, same thing. The second model that watches the agent doesn’t even judge these reads, only what the agent then does with the key.

The mode is the “call me before you knock down a wall” note left for the contractor. It doesn’t stop them from opening your drawers. And the working directory boundary is code, so it can fail. In 2025, Elad Beber, at Cymulate, found a hole in it, fixed since.

The mode decides who approves actions. It doesn’t decide what the agent is allowed to read. For that, you need written deny rules.


The bare minimum in 15 minutes

Three settings, in a single file, ~/.claude/settings.json. Start in Manual, remove auto mode, and block reads of your keys, your .env files and your personal folders.

This file applies to the Claude app as well as the terminal. Anthropic spells it out, the app reads the same settings.

1. Open the settings file

Even if you only use the app, open the Terminal once (Applications, then Utilities) and paste these two lines.

mkdir -p ~/.claude && touch ~/.claude/settings.json
open -e ~/.claude/settings.json

The first creates the file if it doesn’t exist, without touching an existing one. The second opens it in TextEdit.

2. Paste the settings

If the file is empty, paste this block as is, without retyping anything.

{
  "permissions": {
    "defaultMode": "default",
    "disableAutoMode": "disable",
    "deny": [
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Read(~/.gnupg/**)",
      "Read(~/Library/Keychains/**)",
      "Read(//**/.env)",
      "Read(//**/.env.*)",
      "Read(~/Documents/**)",
      "Read(~/Desktop/**)",
      "Read(~/Downloads/**)"
    ]
  }
}

If the file already contains settings, keep them and add these lines inside its permissions block. Every line ends with a comma, except the last one of its list. Before typing anything, turn off TextEdit’s smart quotes, Edit menu, then Substitutions, and uncheck “Smart Quotes”. A single curly quote, and Claude Code ignores the whole file.

Save with Cmd+S. Here is what you just set, in plain words.

  • defaultMode starts every session in Manual.
  • disableAutoMode removes auto mode, in the terminal at least (the app, we’ll come back to it). It also guards against a downloaded project that would try to force it on you, more on that below.
  • The first four deny rules close your keys. SSH, access to Amazon’s cloud (AWS), GPG signatures, and the macOS keychain files.
  • The next two close every .env on the disk, and their variants like .env.local.
  • The last three close Documents, Desktop and Downloads.

As a bonus, a read deny rule also forbids writing to the same place.

Keep the ~/ and the // as they are. ~/ starts from your home folder, // from the root of the disk. A single / doesn’t start from the root, it starts from the ~/.claude folder, and protects nothing useful.

The keychain can also be queried by the security command, which goes through macOS without naming a file. That one is most likely not covered. Episode 3 deals with secrets.

3. On the terminal side, check

One golden rule, in the app as in the terminal. Always launch Claude Code from a project folder, never from your home folder, the one a fresh Terminal opens in. In Manual, everything in the launch folder can be read without asking.

Start a session with claude. At the bottom, the status bar should show ⏸ manual mode on.

Type /permissions, then move to the Deny tab with the arrow keys. Your nine deny rules are there. Type Read in the search to see only them.

The macOS Terminal. Above, the bare-minimum settings pasted into the file. Below, Claude Code 2.1.309 launched from the test-canari folder, and at the bottom the status bar "manual mode on".

Settings pasted, session launched from the project folder, status bar in Manual.

Claude Code in the Terminal, /permissions box on the Deny tab, filtered on "Read". The nine deny rules show up, from the .env files to Library/Keychains.

The nine deny rules, in the Deny tab of /permissions.

On Pro, Max and Team plans, Claude Code may offer once to switch your setting to auto. Say no. Your file then stays as it is.

4. On the app side, the folder trap

In the Code tab, the small mode button, under the input box, next to the folder name, opens the “Permissions” menu. On a new folder, the app shows Auto until you click “Trust workspace”. Once trust is granted, it reads your file and Manual is checked.

The trap is elsewhere. The app remembers the mode chosen for each folder, and that choice takes precedence over your file. If you once picked Auto or Accept edits for a folder, the app may keep using it there. Only Plan isn’t remembered.

And disableAutoMode doesn’t hold in the app the way it does in the terminal. Anthropic writes that it removes Auto from the app’s selector. On my Mac, on October 23, Auto was still in the menu, and an “Enable auto mode” button even showed up in the middle of the screen. Don’t touch it. The safest move is to reopen every folder you’ve already worked in, once, and pick Manual. Anthropic documents no way to reset everything at once.

The Claude app, Code tab, on the test-canari folder. The "Permissions" menu is open, Manual is checked, and Auto is still in the list. In the middle, an "Enable auto mode" button is still offered.

Manual is indeed checked, but Auto stays in the menu, and the app even offers to turn it on.

Your deny rules also apply in the app, Anthropic says so. On the other hand, /permissions doesn’t exist there. To see your rules, go through the terminal.

5. Test

Paste these three lines into the Terminal. They create a test-canari folder, outside Documents and Desktop or the test would prove nothing, put a .env with a fake value in it, and launch Claude Code inside.

mkdir -p ~/test-canari && cd ~/test-canari
echo "FAUSSE_CLE=canari-123456" > .env
claude

Ask “show me the contents of the .env file”, then “run cat .env”. Do the same in the app, on the same test-canari folder.

It should refuse both times, in the app as in the terminal. On my machine, the terminal refused flatly, “Permission to use Bash with command cat .env has been denied”. In the app, the read shows “Failed”, the cat “Blocked”, and the agent adds that it won’t look for another way. The model sometimes refuses on its own, out of caution. What matters is that the refusal cites your permission settings.

Claude Code in the Terminal. Asked to run cat .env, the agent answers that the command was denied by the permission settings and that it won't try to read the file another way.

In the terminal, cat .env is denied by the rule, and the agent stops there.

The Claude app, Code tab. Asked to show the contents of the .env file, the read shows "Failed" and the agent explains that the permission settings block this file, without trying to go through cat.

In the app, reading the .env fails, and the agent doesn’t look for another door.

If it doesn’t work

The status bar doesn’t show “manual mode on”. The file isn’t being read, most often because of a comma or a curly quote. Run claude doctor in the Terminal, it reports the settings it rejects, then paste the block again without retyping it.

The version shown is old. Another Claude Code, installed with Homebrew or npm, can take precedence over the installer’s one. claude --version tells you which one launches, which -a claude lists them all. Keep the one in ~/.local/bin, the one Anthropic recommends, and remove the others.

The agent still shows the .env. Check that you saved the file and opened a new session. Then look at how it read it. A grep -r or a script slip under the deny rules, that’s the limit detailed below.

Claude Code can no longer read your projects. They’re probably in Documents, Desktop or Downloads. Remove the matching line, or move your projects. Same thing for .env.*, which also blocks a project’s .env.example.

Fifteen minutes, and the agent no longer opens what’s none of its business. Almost.


Going further

Deny, ask, allow

The file accepts three lists. deny refuses, ask asks you every time, allow lets it through without asking.

Claude Code always reads them in that order, deny first. So an allow can never reopen a deny. And a deny rule holds in every mode, even bypassPermissions, the no-safety-net mode that never asks anything.

It’s the software that enforces these rules, not the model. Writing “never read my keys” in your CLAUDE.md file is an instruction it may follow. A deny is a guaranteed refusal. As for a .claudeignore file, it has no effect.

Projects have their own settings too

A project can have its own settings, in its .claude folder. The lists from all the files add up, and a deny rule set anywhere can’t be lifted by any other file.

That’s why your deny rules go in your personal file. They follow you everywhere, and a downloaded project can neither cancel them nor force the no-safety-net mode.

Auto mode, though, it can. A project that writes it in its settings makes Claude Code ignore your defaultMode, and it falls back on its starting mode, auto. Hence the disableAutoMode in the bare minimum. It can also force Accept edits on you, which approves file changes on its own, so check the status bar when you open an unknown project. Booby-trapped projects have other tricks up their sleeve, that’s episode 2.

What slips under the deny rules

A read deny rule stops Claude’s read tool, and the file commands it recognizes in the terminal, like cat .env, head or tail.

It doesn’t stop a command that reads without naming the file. A grep -r that searches a whole folder, or a small Python script that opens the files itself. Anthropic admits it in its docs.

I checked it on October 19, in Manual, with the nine deny rules in place, on the trap repository from episode 0. cat .env, denied. grep -r METEO_API_KEY ., which searches for the name of the fake key, went through without asking anything, and the key came out in full. The Python script, for its part, ran into a permission prompt. In a normal session, one absent-minded click, and it went through too.

Google has a public example. In November 2025, PromptArmor showed that its coding agent, Antigravity, worked around its own block by simply going through cat. The file tool says no, the agent looks for another door.

Claude Code’s sandbox closes that door. It relies on the isolation built into macOS and locks up every command the agent runs, scripts included.

Three things to know. It’s off by default. Even when it’s on, it still lets the agent read almost the whole machine, ~/.ssh included, as long as you don’t tell it what to close. And it doesn’t watch Claude’s read tool, which only your deny rules govern. So you need both layers.

Here is the complete file, to put in place of the previous one. Your three bare-minimum settings are in it, unchanged.

{
  "permissions": {
    "defaultMode": "default",
    "disableAutoMode": "disable",
    "blockReadsOutsideWorkingDirectories": true,
    "disableBypassPermissionsMode": "disable",
    "deny": [
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Read(~/.gnupg/**)",
      "Read(~/Library/Keychains/**)",
      "Read(//**/.env)",
      "Read(//**/.env.*)",
      "Read(~/Documents/**)",
      "Read(~/Desktop/**)",
      "Read(~/Downloads/**)"
    ]
  },
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": ["~/**/.env", "~/**/.env.*"]
    },
    "credentials": {
      "files": [
        { "path": "~/.ssh", "mode": "deny" },
        { "path": "~/.aws", "mode": "deny" },
        { "path": "~/.gnupg", "mode": "deny" }
      ]
    }
  }
}

What gets added, in plain words.

  • blockReadsOutsideWorkingDirectories stops the read tool from reading anything outside the working directory, in every mode. It’s useless if you launch Claude Code from your home folder, hence the nine deny rules we keep.
  • disableBypassPermissionsMode removes the no-safety-net mode.
  • The sandbox block turns the sandbox on, refuses to work if it doesn’t start, and forbids getting out of it.
  • denyRead and credentials block commands from reading the .env files in your home folder, and your SSH, cloud and GPG keys.

If you add your own paths to the sandbox block, careful, it’s written the opposite way from the deny rules. A single / there does start from the root of the disk.

The price is real. This strict mode breaks some tools, git over SSH, open, docker, and the docs detail the workarounds. You also need Claude Code 2.1.309 or later, claude --version gives you yours. 2.1.299 fixed a denied path leaking through a symbolic link, and 2.1.309 stopped shell startup files from running outside the sandbox.

To check, ask Claude to run touch ~/sandbox-probe. Expected answer, Operation not permitted, which is what I got. Typing it yourself tests nothing, it doesn’t go through the agent. And do launch Claude Code from a project folder. From your home folder, the touch goes through, since the sandbox lets the agent write in the working directory, so in your whole home folder. I checked it, by mistake.

Claude Code in the Terminal. The command touch ~/sandbox-probe fails in red with "Operation not permitted". The agent explains that commands can only write in the project folder and the temporary folders.

Sandbox on, macOS refuses writes outside the project.

On the app side, the sandbox applies too. The same touch, requested in the Code tab, got the same Operation not permitted, and the agent stated it couldn’t turn it off. Along the way, macOS may ask you whether “claude” is allowed to access your Documents or a network volume. Answer “Don’t Allow”, your deny rules already close Documents to the agent.

The Claude app, Code tab. The command touch ~/sandbox-probe fails with "Operation not permitted". The agent explains that the sandbox limits writes to the project folder and that it can't turn it off.

The sandbox holds in the app too. Writing outside the project is refused by macOS.

Two blind spots to know about. A local MCP server, your agent’s hookup to an outside tool, runs outside the sandbox with all your rights, one more reason not to install any third-party ones. And for an individual on Pro or Max, a mod, the kind of plugin that ships code, can approve what a deny rule forbids. Episode 2 takes care of it.

A macOS account just for the agent

That’s my recommendation, not Anthropic’s, which leans toward containers and virtual machines. Run the agent in a standard macOS account, separate from the one where your documents live. The agent doesn’t see your documents there, and a standard account can neither create other accounts nor touch their settings, an administrator can.

It’s not an invisibility cloak. On my Mac, another account can list my home folder and read the files sitting at its root, but can’t get into Documents, Desktop or .ssh.

Read, Stop living as an administrator on your Mac

The SSH key that can’t be stolen

An SSH key stored in the Mac’s Secure Enclave never leaves the chip. Even if the agent reads ~/.ssh, there’s nothing to take, and every use can require your finger. Details come in episode 2.

Read, An AI agent can wreck your fleet. The Touch ID lock.


The canary

The canary is the trap from episode 0. A test repository, a fake key in a .env, and a hidden instruction in the README asking the agent to send that key to an address I monitor. I ran it again with every setting from this episode, from October 16 to 23.

  • No settings, in auto. The agent sniffs out the instruction and sends nothing.
  • No settings, in Manual. It reads the .env without asking and copies the key into its answer. Another time, it didn’t even open it. The model isn’t consistent, all the more reason not to count on it.
  • Bare minimum. cat .env is denied. But grep -r dumps the key in full without asking anything, and a small Python script is one click away from getting through.
  • Complete file, sandbox on. cat, grep -r and the Python script are all blocked by macOS. In the app, the touch is blocked the same way.
  • My everyday settings. Reading blocked by a hook, the layer from episode 2.

No run sent the key, the monitored address received nothing.

The score. No settings, the .env is wide open. With the bare minimum, one door remains, grep -r. With the sandbox, none.

Next episode, we lock down the irreversible. Hooks that say no before a destructive command goes out, booby-trapped repositories that give orders to your agent, and the SSH key it can’t carry away. The canary, for its part, will be back with its new score.


The series map

  • Episode 0, prologue. The three risks and the canary. Read, Your AI agent has the keys to your house
  • Episode 1, beginner. What it can open, against “it reads everything”. You are here.
  • Episode 2, intermediate. The irreversible, against “it obeys what it reads”. Coming soon, Guardrails that say no to your AI agent
  • Episode 3, intermediate. Secrets, against “it reads everything”. Coming soon, Your secrets have no business in your AI
  • Episode 4, intermediate. The network exit, against “it sends things elsewhere”. Coming soon, Your AI agent only leaves through the planned door
  • Episode 5, advanced. The perimeter, against “it obeys what it reads”. Coming soon, Your MCP, write it yourself with your AI
  • Episode 6, advanced. Logs and alerts, all three risks after the fact. Coming soon, Watch your AI agent like an employee

Each episode opens with a bare minimum in 15 minutes. At the end, you leave with the checklist and a free downloadable infographic.


In short

Choosing Manual never protected you from reading. It protects you from actions. What the agent can open is set elsewhere, in deny rules the software enforces, whatever the model feels like doing.

These deny rules let indirect reads through. That’s the sandbox’s job.

Tonight, paste the bare-minimum block, switch your folders back to Manual in the app, and ask the agent for your fake .env. If it refuses, the first layer is in place.

Coming soon, Guardrails that say no to your AI agent

Technical terms? Check the glossary.


Sources

The vendor itself

The researchers who found the flaws

  • PromptArmor, a company specializing in AI security, its demonstration of the .env read through cat in Antigravity, Google’s coding agent.
  • Simon Willison, developer and attentive observer of AI agents, his write-up dated November 25, 2025.
  • Cymulate, a security testing vendor, Elad Beber’s post on escaping Claude Code’s working directory.

Apple